TCP链接的建立和关闭过程

  TCP/IP是现代互联网的基础,而TCP/IP三次握手似乎也是经久不衰的问题。这次就着抓包,把TCP/IP建立连接和拆除连接抓了个包,仔细看看到底是怎么回事儿。

  Windows下面数据流量太多了,于是滚到Linux下面,命令行curl url后用Wireshark抓包,就得到了下面一张图(默认Wireshark显示的序列号是相对序列号)。
TCP-IP

一、三次握手(three-way handshake)

  (1) 客户端向服务端指明端口发送一个SYNC报文段,同时包含初始序列号C_ISN;
  (2) 服务端返回包含客户端初始序列号S_ISN的SYNC报文段,同时包含确认序列号(C_ISN+1);
  (3) 客户端对服务器的初始序列号进行确认,确认序列号为S_ISN+1;

  上面客户端第一个发送SYNC的,称为主动打开,而服务端是接收到SYNC然后再发送SYNC的,称为被动打开,建立连接发送SYNC的时候,必须选择一个初始ISN,这个值一般是一个32bit的计数器,每4ms自动加1。

  下面这张图是《TCP/IP详解》给出的连接建立的过程图和状态图
TCP-IP详解-1

二、数据传输

  服务器和客户端双方不断的收发数据,由于是可靠连接,接收方会根据当前接收到的数据长度加上序列号,发送ACK给对端表示接收到了数据。比如第一幅图客户端向服务端发送GET请求长度是73,所以服务端ACK客户端的序列号是74;服务器返回数据之后,客户端ACK了。
  下面给出一张更清晰的确认状态流程,注意ACK序列号的变化。
TCP-IP ACK

三、四次拆连

  终止连接需要四次交互,是因为TCP是全双工工作的,所以每个方向必须单独的进行关闭(称为半关闭),就是当一方完成了自己的数据发送任务后,就可以发送一个FIN来终止这个方向的连接,而此时另一方向还是可以进行数据传输的。
  第一个发送FIN的称为主动关闭,而对应的一方称为被动关闭。
  (1) 主动关闭方发送FIN报文段;
  (2) 当对端接到FIN后,会发回一个ACK,且确认序列号为上次FIN序列号+1;

  下面这张图是《TCP/IP详解》给出的拆除建立的过程图和状态图
TCP-IP详解-2

  从上面的过程中,还可以看出的是,SYNC、FIN报文是占用1个序列号的(1个字节长度),而ACK是不占用序列号的。

四、TCP/IP开发时候的“槽点”

  (1) 前面看了TCP的半连接,所以服务端创建socket的时候还是用上SO_KEEPALIVE参数吧;
  (2) 对于某些类型的网络应用,比如之前的代理程序,记得创建完socket之后设置TCP_NODELAY参数;

本文完!

参考