进程间传递文件描述符有什么实际应用场景呢?
- 最近看到golang中关于服务器平滑热重启reload时,需要长链接不被断开,需要fork一个子进程出来,然后把父进程的所有socket的文件 描述符(即:所有hold的客户端连接)都传递到子进程。在没研究linux进程间传递文件描述符之前,我的脑海里只有fork时,发生copy-on-write,父子进程间直接就可以共享连接fd了,但是这个时候,如果父进程退出,那所有的连接也被掐断了,因为父子进程共享连接资源了。所以需要将fd关联到的资源完整的clone到子进程中,使得父子进程对应的fd完全脱离关系,不过fd从父进程copy到子进程之后,想要fd值(int)都保持一致,不太可能,因为子进程要重新分配fd的。
- 大概就是通过unixsockt,一端sendmsg, 另外一端recvmsg,但是不是简单的传输消息内容,需要告诉内核传输的是文件描述符 SCM_RIGHTS。 下面直接给出php版本的demo
<?php $fds = []; $ret = socket_create_pair(AF_UNIX, SOCK_DGRAM, 0, $fds); if (!$ret) { exit(socket_strerror(socket_last_error())); } $pid = pcntl_fork(); if ($pid > 0) { socket_close($fds[0]); $handle = fopen(__DIR__ . '/atomic.txt', 'a+'); var_dump($handle); socket_sendmsg($fds[1], [ 'control' => [ [ 'level' => SOL_SOCKET, 'type' => SCM_RIGHTS, 'data' => [$handle] ] ] ], 0); sleep(1); } else { socket_close($fds[1]); $data = [ 'controllen' => socket_cmsg_space(SOL_SOCKET, SCM_RIGHTS, 1) ]; $result = socket_recvmsg($fds[0], $data, 0); var_dump("recv ok\n"); var_dump($data['control'][0]['data'][0]); fwrite($data['control'][0]['data'][0], 'passing fd in PHP' . PHP_EOL); }上述代码中,父进程var_dump($handle),和子进程var_dump($data['control'][0]['data'][0]); 两次打印的resource资源类型int值已经变化了,说明fd已经完整clone过去,父进程退出,也不会影响子进程的这个fd了。