golang使用linux共享内存及信号实现崩溃重启

最近项目里有用到共享内存,来实现程序崩溃自启,具体做法就是建立一个守护进程,守护进程实时监测一片共享内存,发现有程序崩溃的时候往里写的数据是某个程序崩溃前写进去的,就把程序重新拉起来

第一步:拦截程序崩溃的信号

要实现程序意外崩溃的时候往共享内存里写东西,首先就要拦截那个让它崩溃的信号,自行处理,比如数组越界,往关闭的套接字里写数据,不小心除了一个为0的数等等,上代码

func RegisterSignal() {
    //注册感兴趣的信号
    signal.Notify(SigChan,
        syscall.SIGBUS,  //总线错误
        syscall.SIGABRT, //调用abort
        //      syscall.SIGTERM, //杀死,测试用
        syscall.SIGSEGV, //访问无效内存
        syscall.SIGILL)  //栈溢出

        //忽略掉其他信号
    signal.Ignore(syscall.SIGHUP, //终端挂起
        syscall.SIGPIPE) //管道错误
}

这是一个系统启动的时候就需要调用的函数,signal.Notify函数主要添加你要拦截的信号,而Ignore函数主要是用来忽略掉一些信号,注册的信号用SigChan来进行接受,以上为几个常用的引起崩溃的信号,有自己的信号也可以进行注册,比如说你可以定义一个78的信号用于在程序中出现某步不得不结束程序的操作,然后先把该信号注册起来,对应的地方把信号发出来,程序就能捕获到

第二步:捕获到程序崩溃的信号

这一步没什么讲的,就是程序开一个chan然后等待chan里面发送数据

select {
    case sig := <-SigChan:
        fmt.Println("recived a signal:", sig)
        CoreDump()
    }

然后就调用一个自己定义的CoreDump函数进行崩溃前处理

第三步 操作共享内存

先上代码:

func CoreDump() {
    fmt.Println("core dump.....")

    fd, err := syscall.Open("/dev/shm/usdeamon", syscall.O_RDWR, 0666)
    if err != nil {
        fmt.Println("open shm file error:", err.Error())
        return
    }
    bs, err := syscall.Mmap(fd, 0, 32, syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED)
    if err != nil {
        fmt.Println("mmap error:", err.Error())
        return
    }

    in := "iftttServer"
    inByte := []byte(in)

    copy(bs, inByte)

    os.Exit(-1)
}

1.由于golang里不带shm_open函数,所以只能使用系统带的open函数进行文件打开,关于shm_open的相关信息此处不再赘述,open函数返回了一个文件描述符供mmap函数调用
2.syscall.Mmap函数跟linux系统调用的mmap函数入参几乎一样,只不过返回值多一个err用于判断是否出错 ,这一步要注意的一点是:
mmap里面的prot字段要和open里面的mode字段想对应,大体来说就是:open的时候开了读写和prot的读写要一致,否则容易引起错误,导致mmap执行失败
3.然后就是利用返回来的Byte数组写东西了 你往[]byte里拷贝的数据都会映射到那个文件里去,读者可以自己实验一下,当程序执行了coreDump之后,手动cat一下那个对应的文件
到这里,golang往里写的部分就完成了,下一篇计划讲解守护进程创建文件和把程序启动.