TCP报文格式参考这篇博客
一、TCP连接
TCP建立连接的过程叫做握手,握手需要在客户端和服务器之间交换三个TCP报文段来完成,这就是TCP三次握手。
1.A主机向B发送连接请求报文段,这是首部中的同步位SYN=1,同时选择一个初始序号seq=x,TCP规定,SYN报文段(即SYN=1的报文段)不能携带数据,但是需要消耗掉一个序号。A主机进入SYN-SENT(同步已发送)状态。
2.B主机收到请求报文后,如果同意建立连接,则向A发送确认报文。在确认报文段中应把SYN位和ACK位都置为1,确认号是ack=x+1,同时也为自己选择一个初始序列号seq=y。这时候主机B进入了SYN-RCVD(同步收到)状态。
3.A主机收到B主机发送的确认报文后,还要跟B主机确认,确认报文段的ACK置1,确认号ack=y+1,而自己的序号seq=x+1。A进入ESTABLISHED(已建立连接)状态。当B收到A的确认报文后,也进入ESTABLISHED状态。
二、TCP释放连接
TCP链接释放过程比较复杂,我们结合双方状态的改变来阐明链接释放的过程。
数据传输结束后,通信双方都可释放链接。现在A和B都处于ESTABLISHED状态。A的应用进程先向其TCP发出连接释放报文段,并停止再发送数据,主动关闭TCP连接。A把连接释放文段首部的终止控制位FIN置为1,其序号seq=u,(它等于前面已传过的数据的最后一个字节的序号加1)这时A进入FIN-WAIT-1(终止等待1)状态,等待B的确认。
B收到链接释放报文段后即发出确认,确认号是ack=u+1,而这个报文的序号是v,等于B前面已经传送过的数据的最后一个字节的序号加1。然后B进入了CLOSE-WAIT(关闭等待)状态。这时的TCP连接处于半关闭(HALF-CLOSE)状态。即,A已经没有数据要发送了,但是B有数据发送,A还是会接收。也就是说从B到A的连接并没有关闭,这个状态可能会持续一段时间。
A收到B的确认后,就进入FIN-WAIT-2(终止-等待-2)状态,等待B发出连接释放的报文。
若B已经没有要向A发送数据,其应用进程就通知TCP释放连接。这时B发出的连接释放报文必须使FIN=1。现假定B的序号为w(在半关闭状态B可能又发送了一些数据)。B还必须重复上次已发送过的确认好ack= u+1。这时B就进入LAST-ACK(最后确认)状态,等待A的确认。
A收到B的连接释放报文段后,必须对此发出确认,在确认报文段中把ACK置为1,确认号ack=w+1,而自己的序号是seq=u+1。然后进入TIME-WAIT(时间等待)状态。请注意,现在的TCP连接还没有释放掉。必须经过时间等待计时器(TIME-WAIT timer)设置的时间2MSL后,A才进入到CLOSED状态。时间MSL叫做最长报文段寿命(Maximum Segment Lifetime),通常是两分钟。因此,A进入到TIME-WAIT状态后,要经过4分钟才能进入到CLOSED状态,才能开始建立下一个新的连接。
问题:为什么A在TIME-WAIT状态必须等待2MSL时间呢?
为了保证A发送的最后一个ACK报文能够到达B。这个ACK报文有可能丢失,因而使处于在LAST-ACK状态的B收不到A发送的FIN+ACK报文段的确认。B会超时重传这个FIN+ACK报文段,A就能在2MSL时间内收到这个重传的FIN+ACK报文段。接着A重传一次确认,重新启动2MSL计数器。最后A和B都正常进入到CLOSED状态。如果A在TIME_WAIT状态不等一段时间而是在发送完ACK报文段后立即释放连接,那么就无法收到B重传的FIN+ACK报文段。B就无法按照正常步骤进入CLOSED状态。