> ## Content Index
> Fetch the complete content index at: https://blog.hacking.pub/llms.txt
> Use this file to discover other available public pages before exploring further.

# tcp连接迁移
- URL: https://blog.hacking.pub/2019/12/14/tcplian-jie-qian-yi/
- Published: 2019-12-14T06:02:56.000Z
- Updated: 2019-12-18T16:47:28.000Z
- Author: chainhelen

#### 意义

搜了一下好像并没有文章讲这件事，网上的`tcp迁移`貌似讲的都是网关，跟`upstream`直连偷偷换连接（偷改四元组，类似负载均衡）;；不过我说的可能跟其他人看到标题时候想的也不一样，实际主要说的是热更新tcp长链不断。

#### mosn

主要也是看了[mosn](https://github.com/sofastack/sofa-mosn?ref=blog.hacking.pub)（蚂蚁版本envoy）源码，这块挺有意思的。  
实际上我也没有完全看明白它的实现，里面代码封装太多层（抽象，也不好调试）。比方说，`conntion`迁移的时候是和`reader buffer`的数据一起过去了，如何避免中间时间差的`read buffer`；我只是翻懂了大致的思路，然后自己写出来一个（写法上有一些差异）。

#### 热更新

关于热更新：类似nginx或者go http服务的热更新，一般都比较熟知大致流程；  
新进程继承listen port（子进程继承），并且接受新的http请求；  
旧进程上面已存在的http请求正常运行至结束，旧进程在所有http请求关闭后自动退出；  
所以新旧进程短时间可能会同时存在运行。

可以拿nginx和python来做个试验。

![nginx_python](https://blog.hacking.pub/qiniu/tcp%E8%BF%9E%E6%8E%A5%E8%BF%81%E7%A7%BB/nginx_python.png)

第一步：可以看到Nginx监听了80端口，没有任何连接过来  
第二步：利用python的requests库发http请求，注意调用session()是为了保持tcp暂时不断  
第三步：可以看见tcp已经保持不断，随后`nginx -s reload`平滑重启nginx，发现旧进程上面的长链tcp服务器端主动断了

#### tcp长链不断

新旧进程间如何保证tcp长链不断？  
主要利用Linux可以发送 control message 格式，来传递fd（包括listener/tcp conntion 都是可以的）  
需要注意一些细节，例如`read buffer`传过去的时机；又或者因为现在的`tcp`是双工的，所以对于`write`的`conntion`是不需要重复传输`conntion`的，`read`的`conntion`已经发送过一遍了。

#### reply

我写了一个极小demo，留作记录  
我的程序会指定监听端口，当客户端连接上来的时候，无论发送过来，只有看到'#'，就会把字符串截取加上指定的前缀吐出去

举个栗子

```
// 程序编译、运行  
go build -o main 
./main -l :8081 -p hello 
// 然后就不用看上面服务端的日志，主要看下面客户端返回

// 客户端使用nc连接并发送数据  
nc 127.0.0.1 8081
// 发送
123#456#789
// 收到
hello reply : 123#
hello reply : 456#

```

因为`789`后面没有'#'号，所以程序并没有把 `789` 返回

```
// 这个时候启动新的进程
./main -p world

//并且把`789`后续的`#`补上发出去，你会发现nc收到了 
world reply: 789#

// 最终旧进程平滑关闭

```

全流程下来 nc 与服务端的连接没有断链（可以任意中途netstat -anp查看连接），tcp保持长链无感

![reply.png](https://blog.hacking.pub/qiniu/tcp%E8%BF%9E%E6%8E%A5%E8%BF%81%E7%A7%BB/reply.png)

##### 附件

[代码下载地址](http://img.hacking.pub/cm2.source.zip?ref=blog.hacking.pub)

附一份代码的流程图，防止忘了

![cm2.png](https://blog.hacking.pub/qiniu/tcp%E8%BF%9E%E6%8E%A5%E8%BF%81%E7%A7%BB/cm2.png)