熟悉 Linux 的开发者都知道,重启系统 sshd 服务时,当前连接是不会丢失的。
比如,在需要修改 sshd 服务端口号的时候,只要修改 /etc/ssh/sshd_config
,然后执行 systemctl restart sshd
即可,当前会话不会有任何中断。
这是因为,OpenSSH
使用了进程模型,主进程只负责端口监听。新连接建立的时候,主进程会 fork 出子进程,并将 TCP 连接传递给子进程处理。主进程停止不影响子进程继续运行,因此重启服务不影响已经建立的会话。
我尝试在 Go 中实现相同的特性,并取得了成功。
我在此简要介绍一下,在 Go 中如何将 TCP 连接传递给子进程。
相关代码在此:antssh/antsshd
1. 区分主进程和子进程
Go 中的 syscall.ForkExec
是真正意义上的 Fork,但是使用起来比较麻烦,因此我选择使用 os/exec
为此,我增加了一个 -worker
参数。主进程会通过 os.Executable()
方法来获取自身可执行文件的完整路径,在创建子进程的时候,会执行相同的命令,并追加该参数。这样,新创建出来的进程就知道自己是子进程了。