18.TCP连接的建立与终止

本文详细介绍了TCP连接的建立与终止过程,包括三次握手和四次挥手的具体步骤,并解析了TCP状态变迁图,深入探讨了TIME_WAIT状态的作用及原因,以及复位报文段的触发条件。

连接的建立与终止

通过如下命令让主机svr4与bsdi发起并终止连接

image_1ciuvborm19vt1c6m1bhb1i8vmt99.png-29.3kB

下面为tcpdump输出的TCP报文段部分

image_1ciuvdlpa1g981ruv11r2104813tem.png-147.2kB

每行格式为源>目的:标志

上图中的标志的解释

image_1ciuvj3se1b7m1qvrvet1gv16ds13.png-82.5kB

  • 第1行,1415531521:1415531521(0)表示分组的开始序号为1415531521,结束序号也为1415531521,数据字节数为0。这是连接同步请求,没有任何数据交换
  • 第2行,ack 1415531522代表确认序号,这个值只有在ACK标志位为1时才显示
  • win 4096表示发送端通告的窗口大小
  • < mss 1024 >表示发送端指明的最大报文长度,发端不接收超过该长度的报文段

建立连接协议

image_1civ1rl5k11e9150i1c4a1g081p001g.png-152.4kB

三次握手:

  1. 客户端发送一个SYN段作为连接请求,初始化序号为1415531521
  2. 服务端响应一个SYN段,初始化序号为1823083521。同时发送确认报文,确认序号为1415531521+1=1415531522。一个SYN占用一个序号
  3. 客户端响应确认报文,确认序号为1823083521+1=1823083522

终止连接协议

一个TCP连接是全双工,数据在两个方向传递,因此如果要关闭TCP连接,必须单独关闭两个方向的连接

四次握手:

image_1civ9i8ha1nq132p1odatjh2531t.png-67kB

  1. 客户端发送FIN,请求关闭连接
  2. 服务端收到FIN后,响应ACK
  3. 服务端发送FIN,请求关闭连接
  4. 客户端收到FIN后,响应ACK

之所以比连接多一次握手,是因为TCP支持半关闭,允许一边关闭连接后另一边仍能发送数据,所以无法合并报文5和报文6,两者之间仍然可能存在单向数据传输的报文。所以一旦使用了半关闭,这四次握手就会分成两个阶段执行

建立连接超时

image_1cj0943mo1t991m4v61ij8k1otd2a.png-165.2kB

其中第1、2次请求间隔5.8秒,第2、3次请求间隔24秒,其中tos 0x10代表telnet将IP数据报服务类型字段设为最小时延

image_1cj0e26n51svo1vkh14eq13dl12f62n.png-81.6kB

上面显示的总耗时76秒,是因为在大多数实现中,新建连接的时间最长为75秒

BSD TCP采用500ms定时器,在初始化设置时,第一个500ms内会在任意时刻滴答一下,导致第一个间隔不是6秒而是5.8秒,但第二个间隔却是准确的24秒

image_1cj0ecv2o1km66if8fe1tfe40734.png-123.5kB

最大报文段长度

MSS,表示TCP传往另一端最大数据块的长度。当建立TCP连接时,双方都要通告各自的MSS。如当A告知B MSS为1460时,表示B可以发给A的最大数据块长度就是1460

通常以太网将MSS设为MTU大小减去IP首部和TCP首部长度,即1500-20-20=1460

TCP的半关闭

TCP提供了发送端在结束发送后,依然可以接收数据的能力,这就是半关闭

在应用程序调用shutdown,并且第二个参数为1时,会使用半关闭。普通的close不会有半关闭。所以很少应用程序会使用到半关闭

为什么要有半关闭?

image_1cj0lsfdthsnhlacpc62p1mih9.png-162.3kB

场景:当发送远程命令到目的主机执行时,命令发送完后,client就能结束数据发送,但仍然接收目的主机发回的执行结果,这就是半关闭状态,当目的主机发完数据时,结束数据发送,完成连接关闭。没有半关闭,目的主机无法知道client数据什么时候发完,也就无法执行命令并响应结果

TCP状态变迁图

image_1cj0m8gfv1pd89b81geukgs9aum.png-518.5kB

其中SYN收到就是SYN_RCVD

image_1cj0nsuqiirt1k2v1ng31dob1ped1g.png-185.3kB

通过上面两个图可以观察到

  • client从CLOSED到ESTABLISHED所需要发送和接收的报文
  • server从LISTEN到ESTABLISHED所需要发送和接收的报文
  • ESTABLISHED状态才能进行数据传输
  • client从ESTABLISHED到CLOSED所需要发送和接收的报文
  • server从ESTABLISHED到CLOSED再到LISTEN所需要发送和接收的报文

并不存在CLOSED这个状态,它是一个假象的状态起点和终点,所以server从CLOSED过度到LISTEN不需要特殊处理

TIME_WAIT状态

又称2MSL等待状态,即2倍的报文段最大生存周期

当TCP主动关闭一方发送最后一个ACK时,会进入TIME_WAIT状态,等待2MSL时间才能彻底关闭连接

为什么需要等待2MSL呢?

  1. 防止最后一个ACK丢失。如果真丢失,被动关闭一方会重发FIN(2MSL=MSL(丢失的ACK)+MSL(重发的FIN)
  2. 在2MSL期间不能复用连接(源IP、目的IP、源端口、目的端口的四元祖),避免原始连接中迷途的数据跑到新连接中

大部分TCP实现较为严格,在TIME_WAIT期间,无法复用端口

  • 如果客户端主动关闭连接,进入TIME_WAIT,由于客户端是随机端口,无法复用原来端口可以很容易做到
  • 如果服务端主动关闭连接,进入TIME_WAIT,由于服务端是知名端口,无法复用原来端口会导致重启服务耗时至少为2MSL。很多实现提供SO_REUSEADDR来绕过这个限制,保证服务端可以复用TIME_WAIT期间的端口

FIN_WAIT_2状态

当主动关闭一方发送FIN,并收到ACK后,会进入FIN_WAIT_2状态,直到被动关闭一方发送FIN,主动方才会响应ACK并进入TIME_WAIT状态

所以,如果被动关闭一方不关闭连接,会导致主动关闭一方永远处于FIN_WAIT_2状态,而被动关闭一方永远处于CLOSE_WAIT状态

复位报文段

当报文段发往一个socket时出现错误,TCP就会发出一个复位报文段。通常有以下三种场景:

  1. 到不存在的端口发起连接请求。当发送到目的端,发现端口不存在,UDP会响应一个ICMP端口不可达差错,TCP会响应复位报文段
  2. 异常终止一个连接。通过FIN正常关闭,但是需要处理排队的数据;复位报文段异常关闭,可以立即丢弃排队的数据
  3. 检测半打开连接。当一边异常关闭连接而另一边不知道,这种是半打开连接。如server异常断电重启,client不知server的状况,继续发送报文,server收到后立马响应一个复位报文段

TCP选项

image_1cj94hccc4vb1r2m5je1u281as8p.png-89.3kB

如图显示了三个选项:

  1. 最大报文段长度
  2. 窗口扩大因子
  3. 时间戳

实际为了保证选项总长度是4字节的倍数,需要在其中填充无操作NOP选项

image_1cj94lvah1gjrf8lck71c6g1pq526.png-15.9kB

TCP服务器的设计

  • 当服务端监听连接时,会处于LISTEN状态
  • 当客户端请求到来时,会启动一个线程/进程去接收客户端连接请求
  • 当客户端服务端连接建立时,处于ESTABLISHED状态

image_1cjfq6vjkc5otqo1at41vtqcsi19.png-50.8kB

服务器可以限定本地监听的IP地址和远端请求的IP地址

连接队列

当服务器忙于处理客户端请求时,多的请求在连接建立后会放入连接队列。连接队列有以下规则:

  1. 监听连接请求的一端会有固定长度的连接队列,该队列存储已建立连接(完成了三次握手)的请求,稍后应用程序会从该队列中移除请求并处理
  2. 积压值(backlog)是这个队列的最大长度
  3. 当该队列已满,TCP不会将理会后续的连接请求(SYN),并且不会回复RST。RST代表这个请求是硬错误,不能重试。而不理会会让客户端请求超时,发现是一个软错误,会进行重试

转载于:https://my.oschina.net/u/1378920/blog/1913445

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值