我已经被这个问题困扰了几个小时了:
我有一个主进程充当TCP服务器,主进程调用Fork(),将其net.Listener()的FD传递给子进程。然后,子进程可以使用net.Filelistener()继承此FD。
我已经通过许多开源代码研究了这个问题,还做了一些实验。但是不幸的是,这些解决方案目前尚不满足我的需要,因为它们不便于携带,您还需要许多危险的低级工作。
如果有任何将net.Listener()的FD传递给子进程SAFELY的解决方案,我很高兴知道。
我现在尝试过的是:
环境值(非可移植性)会导致许多FD混乱,这是不安全的,因为可以从外部进行更改。
Dup FD&Clear FD_CLOEXEC然后是exec / fork,可移植,但不受Go API支持,syscall.NoCloseOnExec()提交给开发团队的更改被拒绝,因为他们希望保持syscall清洁。
FD_CLOEXEC
syscall.NoCloseOnExec()
设置为SO_REUSEADDR使子进程可以立即监听端口,然后关闭父监听器。失败,不可移植,Go API不支持,也不安全。
SO_REUSEADDR
exec.Command.ExtraFiles(),不知道如何从子进程中继承FD,我是否需要一个配置文件来保存FD和名称?此解决方案也有一个错误,有关更多详细信息,请阅读exec的文档。
exec.Command.ExtraFiles()
好的,我已经写了这个问题的简单测试案例(使用解决方案4):
https://github.com/reckhou/go-fd-pass-test
还包括OS X和Linux上的2个可执行文件。我尝试了Go 1.1和Go 1.1.1,但此问题仍然存在。
最简单的方法是在exec.Cmd的ExtraFiles字段中传递侦听器。
父母的例子:
var l *net.TCPListener cmd := exec.Command(...) f, err := l.File() cmd.ExtraFiles = []*os.File{f}
孩子的例子:
l, err := net.FileListener(os.NewFile(3, "listener"))
您可能还需要对此进行概括,并让孩子接受PROGRAMNAME_LISTENER_FD作为环境变量。然后,父级将在启动子级之前将环境变量设置为3。