为了提供可靠的传送,TCP在发送新的数据之前,以特定的顺序将数据包的序号,并需要这些包传送给目标机之后的确认消息。TCP总是用来发送大批量的数据。当应用程序在收到数据后要做出确认时也要用到TCP。

在TCP/IP中,采用三次握手来建立一次连接。

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,两者可以进行数据交换了,完成三次握手。

三次握手四次断开_第1张图片

三次握手四次断开_第2张图片

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。四次断开过程如下:
(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送,提出断开连接要求。
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。确定这一方连接将关闭。
(3) 服务器关闭客户端的连接,发送一个FIN给客户端,请求关闭连接。
(4) 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。

采用三次握手是为了防止失效的连接请求报文段突然又传送到服务器端,因而产生错误。
三次握手四次断开_第3张图片

在第四步时,为什么需要TIME_WAIT?HOST1发送的ACK可能丢失并导致HOST2重新发送FIN消息,TIME_WAIT维护连接状态。如果执行主动关闭的一方HOST1不进入到TIME_WAIT状态就关闭连接,当重传的FIN消息到达时,因为TCP已经不再有连接的信息了,所以就用RST(重新启动)消息应答,导致HOST2进入到错误的状态而不是有序终止状态。如果发送最后ACK消息的一方处于TIME_WAIT状态并仍然记录着连接的信息,它就可以正确地响应对等方HOST2的FIN消息了。其次,TIME_WAIT为连接中“离群的段“提供从网络中消息的时间。

引申:为什么建立连接是三次握手,而关闭连接却是四次握手?

因为服务端的LISTEN状态下的SOCKET收到SYN报文的建立连接请求后,它可以把ACK和SYN放在一个报文里发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发给你了,但未必你所有的数据都已经发给对方了,所以你未必会马上关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方同意现在可以关闭连接了,所以这里的ACK和FIN报文多数情况下都是分开发送的。