由于 TCP 的特性,包括初次连接的握手、连接后窗口大小的调整、连接后分配的默认缓存(128KB Linux),使得每一路 TCP 的开销都不小。因而如果一个应用的每次数据请求都要开一路 TCP 连接到服务器的话,服务器的压力就会比较大,因而就产生可以将多路请求合并到一路 TCP 上,这样就可以充分利用服务器资源,并能提高访问效率。这个技术叫TCP Multiplex
每一次 SSH 连接也是一个完整的 TCP 通信过程,通过在 ~/.ssh/config 里面的设置可以针对某一路或者多路的连接进行归一化。
Host xxx ControlPath ~/.ssh/controlmasters/%r@%h:%p ControlMaster auto ControlPersist 1h
Host 是要访问的主机域名(也可以是主机名),ControlPath 是 SSH 用来放置连接句柄的位置,ControlMaster 选择默认连接模式,可以在连接前选择是否使用复用的连接,ControlPersist 设置这个复用连接的生效时间。
ssh xxx
访问连接后退出,可以在进程列表里面发现多了一个常驻进程,比如
ssh: ~/.ssh/controlmasters/xxx:22 [mux]
而且在 ControlPath 里面多了一个文件
srw——- 1 users 0 Dec 22 08:24 xxx:22
可以看到这个文件的属性是 s 开头,也就是说它是一个 socket 文件。
查看 SSH 的源代码,可以看到 SSH 连接前通过 ControlPath 的 socket 文件开始了一个服务器,通过这个服务器保持 SSH 的连接,如果再有本机访问就作为这个服务器的Client 先连接到本地这个服务器。服务器是经典的 socket -> fork 结构,在服务器进程 detach 之后,初始进程同时作为一个 client 接入服务器。服务器通过发送过来的信息,决定将信息分发到某个具体的进程或者通道。可以通过 ssh -vvv 得到完整的调试信息。
TCP 多路复用虽然效果很好,但是实现起来难度不小,还有许多注意事项,比如[这个](http://250bpm.com/multiplexing),在缓存的处理上,不能让一个僵死的 client 阻塞了通信,而是要给每个 client 分配单独的缓存。