在做以太网的过程中,借助老衲五木的一些书籍,比较详细的了解了LWIP协议栈建立TCP连接和断开连接的过程,跟踪源码,查看控制块状态转换后的一些理解有必要记录下来。我们都知道TCP建立连接时的三次握手,断开连接时有四次握手:
建立连接时:
首先,请求端(通常称为客户端)发送一个 SYN 标志置 1 的 TCP 数据报,数据包中指明自己的端口号及将连接的服务器的端口号,同时通告自己的初始序号 ISN。当服务器接收到该数据包并解析后,也发回一个 SYN报文段作为应答。该回应报文包服务器自身选定的初始序号 ISN,同时,将 ACK 置 1,将确认序号设置为请求端的 ISN加 1 以对客户的 SYN 报文段进行确认。这里的 ISN 也表示了服务器希望接收到的下一个字节的序号。由此可见,一个 SYN 将占用了一个序号。
最后,当请求端接收到服务器的 SYN 应答包后,会再次产生一个握手包,这个包中,ACK 标志置位,确认序号设置为服务器发送的 ISN 加 1,以此来实现对服务器的 SYN 报文段的确认。
断开连接时:
断开一个连接的四次握手过程如下图所示,首先客户端应用程序主动执行关闭操作时,客户端会向服务器发送一个 FIN 握手包,用来关闭从客户到服务器的数据传送。当服务器收到这个 FIN,它发回一个 ACK,确认序号为收到的序号加 1。和 SYN 一样,一个 FIN 将占用一个序号。同时服务器还向其上层应用程序通告接收到结束动作,接着这个服务器程序就会关闭它的连接,导致它的 TCP 端发送一个 FIN 握手包,客户必须发回一个确认,并将确认序号设置为收到序号加 1。
如下图所示:
在这个图中,发送 FIN 将导致应用程序关闭它们的连接,这些 FIN 的 ACK 是由 TCP 软件自动产生的。连接断开的主动发起方通常是客户端,但如果是服务器首先发起 FIN 包,上图的握手过程也是完全成立的。
一个 TCP 连接是全双工(即数据在两个方向上能同时传递), 因此每个方向必须单独地进行关闭。当发送数据的一方完成它的数据发送任务后它就可以发送一个 FIN 标志置 1 的握手包来终止这个方向连接。当另一端收到这个 FIN包时,它必须通知应用层另一端已经终止了那个方向的数据传送。发送 F I N 通常是应用层进行关闭的结果,收到一个 FIN 意味着在这一方向上已经没有数据流动。一个 TCP 连接在收到一个 FIN 后仍能发送数据,此时的连接处于半关闭状态。通常首先进行关闭的一方(即发送第一个 FIN)将执行主动关闭,而另一方(收到这个 FIN)执行被动关闭。
建立连接控制块状态装换过程(客户端主动连接服务器):
数据收发流程 客户端控制块状态 服务器控制块状态
1、服务器和客户端建立连接时 无 LISTEN
2、客户端发送SYN报文段数据 SYN_SENT 状态不变
3、服务器接收到客户端SYN包并返回确认包 状态不变 SYN_RCVD
4、服务器接收到客户端SYN包并返回SYN+ACK 状态不变 状态不变
5、客户端收到确认包并返回ACK包 ESTABLISHED 状态不变
6、服务器收到ACK包 状态不变 ESTABLISHED
断开连接控制块状态装换过程(客户端主动断开):
当客户端申请断开连接时,它要发送 FIN 包给服务器申请断开连接,当 FIN 包发送后,客户端进入FIN_WAIT_1 状态等待服务器返回确认包,当收到这个确认包后,表明客户端到服务器方向的连接断开成功,此时客户端进入FIN_WAIT_2 状态等待服务器到客户端方向的连接断开,此时当客户端收到服务器的 FIN 包时,即向服务器返回一个 ACK 包,表明服务器到客户端方向的连接断开成功,此后客户端进入 TIME_WAIT 状态,在该状态下等待 2MSL 后,客户端进入初始的 CLOSED 状态。在连接处于 2MSL 等待时,任何迟到的数据报文段将被丢弃。此过程与断开连接的四次握手过程完全相符。
学习LWIP协议栈,更详细内容推荐老衲五木书籍:LwIP协议栈源码详解