TCP通信协议( 二 )


由于一个四元组表示 TCP 连接,理论上服务端可以建立很多连接,服务端确实只监听一个端口 但是会把连接扔给处理线程,所以理论上监听的端口可以继续监听 。但是线程池处理不了那么多一直不断的连接了 。所以当服务端出现大量 TIME_WAIT 时,系统资源被占满时,会导致处理不过来新的连接
③ 如何优化 TIME_WAIT?
这里给出优化 TIME-WAIT 的几个方式,都是有利有弊:
打开 net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 选项
net.ipv4.tcp_max_tw_buckets
程序中使用SO_LINGER,应用强制使用RST关闭
④ 为什么 TIME_WAIT 等待的时间是 2MSL?
MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃 。因为 TCP 报文基于是 IP 协议的,而 IP 头中有一个 TTL 字段,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机 。
MSL 与 TTL 的区别: MSL 的单位是时间,而 TTL 是经过路由跳数 。所以 MSL 应该要大于等于 TTL 消耗为 0 的时间,以确保报文已被自然消亡 。
TIME_WAIT 等待 2 倍的 MSL,比较合理的解释是: 网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间 。
比如如果被动关闭方没有收到断开连接的最后的 ACK 报文,就会触发超时重发 Fin 报文,另一方接收到 FIN 后,会重发 ACK 给被动关闭方,一来一去正好 2 个 MSL 。
2MSL 的时间是从客户端接收到 FIN 后发送 ACK 开始计时的 。如果在 TIME-WAIT 时间内,因为客户端的 ACK 没有传输到服务端,客户端又接收到了服务端重发的 FIN 报文,那么 2MSL 时间将重新计时 。
在 Linux 系统里 2MSL 默认是 60 秒,那么一个 MSL 也就是 30 秒 。Linux 系统停留在 TIME_WAIT 的时间为固定的 60 秒 。
其定义在 Linux 内核代码里的名称为 TCP_TIMEWAIT_LEN:
#define TCP_TIMEWAIT_LEN (60HZ) / how long to wait to destroy TIME-WAIT state, about 60 seconds */
如果要修改TIME_WAIT的时间长度,只能修改Linux内核代码里TCP_TIMEWAIT_LEN的值,并重新编译Linux内核 。
连接过程

TCP通信协议

文章插图
TCP三次握手
开始客户端和服务器都处于CLOSED状态,然后服务端开始监听某个端口,进入LISTEN状态:
第一次握手(SYN=1, seq=x),发送完毕后,客户端进入 SYN_SENT 状态
第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1),发送完毕后,服务器端进入 SYN_RCVD 状态
第三次握手(ACK=1,ACKnum=y+1),发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手,即可以开始数据传输
TCP通信协议

文章插图
假设一开始客户端和服务端都处于CLOSED的状态 。然后先是服务端主动监听某个端口,处于LISTEN状态
【第一个报文】:客户端会随机初始化序号(client_isn),将此序号置于 TCP 首部的「序号」字段中,同时把 SYN 标志位置为 1,表示 SYN 报文 。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态
TCP通信协议

文章插图
【第二个报文】:服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1, 接着把 SYN 和 ACK 标志位置为 1 。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态
TCP通信协议

文章插图
【第三个报文】:客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1,其次「确认应答号」字段填入 server_isn + 1,最后把报文发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于 ESTABLISHED 状态
TCP通信协议

文章插图
服务器收到客户端的应答报文后,也进入 ESTABLISHED 状态
第三次握手是否可以携带数据?
第三次握手是可以携带数据的,前两次握手是不可以携带数据的 。一旦完成三次握手,双方都处于 ESTABLISHED 状态,此时连接就已建立完成,客户端和服务端就可以相互发送数据了 。假设第三次握手的报文的seq是x+1:


推荐阅读