TCP协议详解二:连接的建立与释放

1. 连接建立的“三次握手”

1.1 三次握手流程

TCP协议详解二:连接的建立与释放

  • 客户端发送SYN,表明要向服务器建立连接。同时带上序列号ISN
  • 服务器返回ACK(序号为客户端序列号+1)作为确认。同时发送SYN作为应答(SYN的序列号为服务端唯一的序号)
  • 客户端发送ACK确认收到回复(序列号为服务端序列号+1)
  • 所以要确保双方,同时能发数据和收数据
  • 第一次握手:证明了发送方能发数据
  • 第二次握手:ack确保了接收方能收数据,syn确保了接收方能发数据
  • 第三次握手:确保了发送方能收数据
  • 实际上是四个维度的信息交换,不过中间两步合并为一次握手了。
  • 四次握手浪费,两次握手不能保证“双方同时具备收发功能”
  • 同时tcp支持半关闭(发送一方结束发送还能接收数据的功能)。
  • 因此每个方向都要单独关闭,且收到关系通知需要发送确认回复
  • 同时仍要接收来自服务端的数据
  • 使用半关闭的单连接效率要比使用两个tcp连接更好
  • 服务端收到FIN后,发送一个ACK作为确认(序列号为收到的序列号+1)
  • 等服务器数据传输完毕,也发送一个FIN标识,表示关闭这个方向的数据传输
  • 客户端回复ACK以确认回复
  • 客户端主动打开请求,发送SYN时处于SYN_SENT发送状态
  • 客户端收到syn和ack,并回复ack时,处与Established状态等待发送报文
  • 服务端收到ack确认后,也处于Established状态等待发送报文
  • 客户端发送fin后,处于fin_wait_1状态
  • 服务端收到fin并发送ack时,处于close_wait状态
  • 客户端收到ack确认后,处于fin_wait_2状态
  • 服务端发送fin后,处于last_ack状态
  • 客户端收到fin后发送ack,处于time_wait状态
  • 服务端收到ack后,处于closed状态
  • 主动关闭的一方发送最后一个ack所处的状态
  • 这个状态必须维持2MSL等待时间
  • 这时候接收方会重新发送fin给发送方
  • 这个等待时间就是为了防止这种情况发生,让发送方重新发送ack
  • 总结:预留足够的时间给接收端收ack。同时保证,这个连接不会和后续的连接乱套(有些路由器会缓存数据包)
  • 很多时候linux上报too many open files,说端口不够用了,就需要检查一些代码里面是不是创建大量的socket连接,而这些socket连接并不是关闭后就立马释放的
  • 客户端连接服务器的时候,一般不指定客户端的端口。因为客户端关闭然后立马启动,按照理论来说是会提示端口被占用。同样的道理,主动关闭服务器,2MSL时间内立马启动是会报端口被占用的错误
  • 多并发的短连接情况下,会出现大量的Time_wait状态。这两个参数可以解决问题,但是它违背了tcp协议,是有风险的。参数为:tcp_tw_reuse和tcp_tw_recycle
  • 如果是服务端开发,可设置keep-alive,让客户端主动关闭连接解决这个问题
  • 异常中止:通过发送RST而不是fin来中止连接
  • 这种情况极少发生
  • 两端同时发送SYN,同时进入SYN_SENT状态
  • 打开一条连接而不是两条
  • 要进行四次报文交换过程,“四次握手”
  • 进行四次报文交换
  • 状态和正常关闭不一样
  • 该队列中的连接为:已经完成了三次握手,但还没有被应用层接收(应用层需要等待最后一个ack收到后才知道这个连接)
  • 应用层接收请求的连接,将从该队列中移除
  • 当新的请求到来时,先判断队列情况来决定是否接收这个连接
  • 积压值的含义:tcp监听的端点已经被tcp接收,但是等待应用层接收的最大值。与系统允许的最大连接数,服务器接收的最大并发数无关