站在运维的角度理解 TCP connect 和 TCP 状态

准备写一个 Linux网络调优,忽然想到很多运维对TCP/IP协议不是很了解,网上的文章也基本不是站在运维的角度来讲述,而且很多有关TCP/IP三次握手,四次断开的文章都是错的(你没有看错,很多写的似很厉害的文章,都是错的),所以还是准备自己写一篇,也加深自己的理解。

注: 本文所有的ClientServer都是广义的,狭义的表示应该是一个套接字,也就是 ip:port

一、TCP 三次握手

第一步:

Client 会向 Server 发送一个有 SYN 标志位的TCP包,表示自己要建立TCP连接。

第二步:

Server 就会返回一个 SYN+ACK 包, ACK 是确认之前 Client 发送过来的 SYN 包, SYN 表示自己也准备好建立连接了。

第三步:

Client 会向 Server 发送一个有 ACK 标志位的 TCP报文,表示自己确认 Server 发送过来的带 SYN 标志位TCP连接请求

在这里要仔细说明一下。Acknowledgment number (确认序列号) 不是 ACK(Acknowledgment),这就是我一开始说的,很多人错的地方。上面我特意把Acknowledgment numberSequence number 没有抹掉的原因。Acknowledgment numberSequence number 就是序列号和确认序列号,用来确认序列的。而所谓的SYNACK。其实就是一个标志位。也就是下面图中的 TCP Flags,实际上就是六位二进制表示的。标志位所在位为0就是Not set,标志位所在位为1就是Set,从上面Wireshark抓的包也可以看出来。0x012不就是001010,对应下图不就是ACK + SYN吗。

(注: 上图我是从 images.Google.com 随便找的, 如有侵权请联系 [email protected], 立即更换….)

标志位解释(只解释对我们最有用的,相信太多人字多不看…)

各状态解释:

二、TCP connection 四次断开

四次断开有两种情况,一种是 Client先断开,一种是Server先断开。为什么会出现这两种情况,后面会详细讲述,而且会进行测试,我们先讲述一下在标志位上面的通信

为了表达清楚意思,所以我就不使用 ServerClient,而上图所表示的也没有ClientServer,因为谁都可以先断开

第一步:

先断开端后断开端 发送带 FIN 的TCP报文,表示自己要断开这个 TCP 连接

第二步:

后断开端先断开端 发送带 ACK 的TCP报文,表示自己已经知道对方想要断开连接了。

第三步:

后断开端先断开端 发送带 FIN 的TCP报文,表示自己已经准备好断开连接了,可能有童鞋要问,为什么这个FIN为什么不和上面那个ACK一起就发送过去了呢?两次分开发送不是增加开销吗?这是因为后断开端也需要准备啊。不能你说断开就断开吧,首先我得试一试能不能断开,确定能断开了,我就会发送FIN确定。

第四步:

先断开端后断开端 发送带 ACK 的TCP报文,确认自己已经断开连接,你也可以断开连接了。

我们看一下各状态的状态图:

解释:

PS:

2MSL(Maximum Segment Life 报文最大生存时间):TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的 FIN),MSL过长会导致无用TIME_WAIT过多,大量的Time_wait会带来一些不好的影响,每个TCP连接都有自己的Transmission Control Block,也就是数据结构,在TIME_WAIT状态的时候这个数据结构还没有被释放。

$ sysctl net.ipv4.tcp_fin_timeout  /* 查看MSL */
net.ipv4.tcp_fin_timeout = 60
$ cat /proc/sys/net/ipv4/tcp_fin_timeout  /* 查看MSL */
60
$ sudo vim /etc/sysctl.conf
net.ipv4.tcp_fin_timeout = 20  /* 后面数字可以根据情况来 */
$ sudo sysctl -p

三、运维角度的延伸

3.1 HTTP持久连接(keepalive)

最后到了解释上面为什么是先断开连接后断开连接了。

HTTP1.0的时候,HTTP协议是没有HTTP持久连接 (keepalive,在后面会不加区别的使用keepalive和持久连接)这个概念的,基本传输一个Resocurce,就需要建立一次连接。HTTP 1.1默认启用的HTTP持久连接能够在keepalive_timeout前省去每次传输报文都要建立TCP连接(三次握手)的时间和开销.

非持久连接:

持久连接(少了TCP的三次握手和四次断开):

(注: 上图我是从 images.Google.com 随便找的, 如有侵权请联系 [email protected], 立即更换….)

HTTP1.0基本可以忽略了,所以这里就出现keeplive_timeout就是关键,也就是说ServerClientkeeplive_timeout先到期,谁就发送FIN TCP报文以断开连接。

3.2 keepalive_timeout 测试

HTTP keep-alive connection timeouts
Firefox: 约115秒(定义在about:config中的network.http.keep-alive.timeout)
Chrome:  约320秒
Opera:   约120秒
MSIE:    约60秒(可以在注册表中自定义)
https://support.microsoft.com/en-us/kb/813827

Nginx:   默认值65秒(keepalive_timeout 65s)

Firefox 默认 HTTP connection keep-alive timeout: 115s Firefoxabout:config 中的 network.http.keep-alive.timeout 可以进行修改 

Nginx 可以在 /etc/nginx/nginx.conf 配置配置项 keepalive_timeout 来调整默认 HTTP connection keep-alive timeout

$ vim /etc/nginx/nginx.conf
	keepalive_timeout  65;   /* 可以任意修改 */

Nginx HTTP connection keep-alive timeout 为默认的 65s,使用默认设置的Firefox来访问Nginx,测试是否是Server端先断开TCP连接,能否出现 120S (2MSL)TIME_WAIT

和预料中的一样,出现了TIME_WAIT: 

测试将 Nginx 超时时长调整为 120s, 看是否不出现TIME_WAIT

经过测试,120s无用,设置成130s然后出现Client先断开连接。

如果也是运维,在这个地方就应该思考一下,上面的测试到底说明了什么。

3.2 自定义是否启用 keepalive_timeout

上面说HTTP1.1默认启用的是keepalive。HTTP Hearder中的Connection可以控制,当Connectionclose的时候,就是短连接,当Connectionkeepalive的时候,就是使用长连接。Client可以设置,Server也可以设置。

先测试Client设置Connection: close,这里使用最简单的Telnet:

$ telnet 10.21.56.4 80
HEAD /index.php HTTP/1.1
Host: 10.21.56.4
Connection: close

HTTP/1.1 200 OK
Server: nginx/1.10.1
Connection: close

为了方便大家查看,我把不是很重要的信息全部都删除掉了。上面就可以很清楚的展示,当Connectionclose的时候,双方都会协商使用短连接。

在Server上面进行观测:

netstat -antl | grep 80 | awk '/^tcp/{sum[$NF]++}END{for (i in sum) {printf "%-20s %d\n",i,sum[i]}}'
TIME_WAIT            1
LISTEN               1

发现有一个连接进入TIME_WAIT,也就是说就算是Client协商使用短连接,主动断开连接的还是Server

使用Firefox访问网站, Nginx HTTP响应报文 的 Hearder

HTTP/1.1 200 OK
Server: nginx/1.10.1
Connection: keep-alive

Server端将keepailve_timeout设置为0 $ vim /etc/nginx/nginx.conf keepalive_timeout 0;

使用Firefox访问网站, Nginx HTTP响应报文 的 Hearder

HTTP/1.1 200 OK
Server: nginx/1.10.1
Connection: close

到这里大家肯定对运维需要掌握的TCP/IP部分有了深入的了解。也能看懂netstat -antl中的那些 TCP 状态到底是什么含义了。后面会在此文的基础上讲述一下网络调优。

参考资料:

The TCP/IP Guide - TCP Connection Establishment Process: The “Three-Way Handshake” 

The TCP/IP Guide - TCP Connection Termination 

Wikipedia - Transmission Control Protocol 

《TCP/IP详解 卷一:协议》