最近项目里有用到共享内存,来实现程序崩溃自启,具体做法就是建立一个守护进程,守护进程实时监测一片共享内存,发现有程序崩溃的时候往里写的数据是某个程序崩溃前写进去的,就把程序重新拉起来
第一步:拦截程序崩溃的信号
要实现程序意外崩溃的时候往共享内存里写东西,首先就要拦截那个让它崩溃的信号,自行处理,比如数组越界,往关闭的套接字里写数据,不小心除了一个为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往里写的部分就完成了,下一篇计划讲解守护进程创建文件和把程序启动.