TCP是一个面向连接的传输层协议,所以无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条传输连接。本节将详细讨论一个TCP传输连接是如何建立的。
在TCP/IP协议体系结构中的TCP协议也是使用三次握手(three-way handshake)机制来建立传输连接的,这与在本章前面介绍的OSI/RM传输层为了避免重复连接而采取的三次握手机制是一样的。具体流程如图10-38所示,其实整体过程在上节的图10-37中有全面的体现,这里仅单独把TCP传输连接建立过程列出来。具体步骤如下:
(1)首先是服务器初始化的过程,从CLOSED(关闭)状态开始通过顺序调用SOCKET、BIND、LISTEN和ACCEPT原语创建Socket套接字,进入LISTEN(监听)状态,等待客户端的TCP传输连接请求。
(2)客户端最开始也是从CLOSED状态开始调用SOCKET原语创建新的Socket套接字,然后在需要再调用CONNECT原语,向服务器发送一个将SYN字段置1(表示此为同步数据段)的数据段(假设初始序号为i),主动打开端口,进入到SYN SENT(已发送连接请求,等待对方确认)状态。
图10-38 TCP传输连接建立的三次握手过程
(3)服务器在收到来自客户端的SYN数据段后,发回一个SYN字段置1(表示此为同步数据段),ACK字段置1(表示此为确认数据段),ack(确认号)=i+1的应答数据段(假设初始序号为j),被动打开端口,进入到SYN RCVD(已收到一个连接请求,但未进行确认)状态。这里要注意的是确认号是i+1,而不是i,表示服务器希望接收的下一下数据段序号为i+1。
(4)客户端在收到来自服务器的SYN+ACK数据段后,向服务器发送一个ACK=1(表示此为确认数据段),序号为i+1,ack=j+1的确认数据段,同时进入ESTABLISHED(连接建立)状态,建立单向连接。要注意的是,此时序号为i+1,确认号为j+1,表示客户端希望收到服务器的下一个数据段的序号j+1。
(5)服务器在收到客户端的ACK数据段后,进入ESTABLISHED状态,完成双向连接的建立。
连接可以由任一方或双方发起,一旦连接建立,数据就可以双向对等地流动,而没有所谓的主从关系。三次握手是连接两端正确同步的充要条件,因为TCP建立在不可靠的分组传输服务之上,报文可能丢失、延迟、重复和乱序,因此协议必须使用超时和重传机制。如果重传的连接请求和原先的连接请求在连接正在建立时到达,或者当一个连接已经建立、使用和结束之后,某个延迟的连接请求才到达,就会出现问题。采用三次握手协议就可以解决这些问题。如客户端发送的ACK数据段就是为了避免因网络延迟而导致的重复连接,因为这时客户端就可通过检查ACK数据段中的确认号就可得知该连接请求是否已失效。
【经验之谈】对比图10-38和本章前面的10.2.2节中的图10-20以看出,总体上TCP传输连接的建立与OSI/RM中TP传输协议的传输连接建立过程既存在相似之处(如三次握手机制),又存在较大区别的。主要表现在:①在OSI/RM中,只有DT TPDU和ED TPDU才有序列号,所以在返回的确认类TPDU中是没有TPDU序号的,所以在图10-20中并没有标注确认TPDU的序列号,而TCP传输连接中,每个数据段(无论是否携带数据)都有序列号,都需要标其对应的序列号;②因为在OSI/RM的传输协议中不同服务原语可以使用不同的特定类型TPDU,所以在OSI/RM的TPDU中不存在像TCP数据段中的ACK、SYN等之类的控制位,因为在TCP协议中所有数据段格式是一样的,不同的只是不同类型的TCP数据段的这些字段的取值不同;③TCP传输连接中使用“确认号”字段与OSI/RM TPDU中的“YR-TU-NR”(你的TPDU序列号)字段的功能是完全一样的,都是显示对端希望接收的下一个数据段序列号,暗示该号码前面的所有数据段均已正确接收。
正常情况下,传输连接都是由一方主动发起的,但也有可能双方同时主动发起连接,此时就会发生连接碰撞,最终只有一个连接能够建立起来。因为所有连接都是由它们的端点进行标识的。如果第一个连接请求建立起一个由套接字(x,y)标识的连接,而第二个连接也建立了这样一个连接,那么在TCP实体内部只有一个套接字表项。
当出现同时发出连接请求时,则两端几乎在同时发送一个SYN字段置1的数据段,并进入SYN_SENT状态。当每一端收到SYN数据段时,状态变为SYN_RCVD,同时它们都再发送SYN字段置1,ACK字段置1的数据段,对收到的SYN数据段进行确认。当双方都收到对方的SYN+ACK数据段后,便都进入ESTABLISHED状态。图10-39显示了这种同时发起连接的连接过程,但最终建立的是一个TCP连接,而不是两个,这点要特别注意。
图 10-39 同时发起连接的TCP连接建立流程
从图中可以看出,一个双方同时打开的传输连接需要交换4数据段,比正常的传输连接建立所进行的三次握手多交换一个数据段。此外要注意的是,此时我们没有将任何一端称为客户或服务器,因为每一端既是客户又是服务器。
10.3.7 TCP传输连接的释放
TCP 连接建立起来后,就可以在两个方向传送数据流。当 TCP的网络应用进程再没有数据需要发送时,就可以发出关闭连接命令,释放连接。TCP协议是通过发送FIN字段置1的数据段来作为关闭传输连接的命令,关闭本端数据流的,但是本端仍然还可以继续接收来自对端的数据,直到对端也使用了同样的方法关闭那个方向的数据流,这时整个双方传输连接就彻底关闭了。
相对TCP传输连接建立的三次握手过程来说,TCP传输连接的释放过程要稍微复杂一些,需要经过四次握手过程。这是因为TCP的半关闭(half-close)特性造成的,即因这一个TCP连接是全双工(即数据在两个方向上能同时传递),每个方向必须单独地进行关闭。TCP传输连接关闭的原则是:当一方完成它的数据发送任务后就可以发送一个FIN字段置1的数据段来终止这个方向的数据发送;当另一端收到这个FIN数据段后,必须通知它的应用层“对端已经终止了那个方向的数据传送”。而FIN数据段的发送是由应用层调用CLOSE服务原语的结果。TCP连接释放的四次握手过程如图10-40所示,具体描述如下:
(1)一开始,通信双方都处于ESTABLISHED(连接建立)状态。如果客户端认为数据全部发送完了,想结束本次传输连接,则由应用层的对应应用进程调用CLOSE服务原语,然后向服务器发出一个FIN字段置1的数据段(假设此数据段的序号为m),客户端进入FIN WAIT 1状态,等待服务器的确认。
(2)服务器在收到客户端发来的FIN数据段后,确认客户端没有新的数据要发送了,向客户端发送一个ACK字段置1,确认号为m+1(假设此数据段序号为w,服务器与客户端的数据段序号可以不一样),表示前面的数据已全部收到了,然后进入到CLOSE WAIT(关闭等待)状态。与此同时服务器的TCP实体通知对应的应用层进程,释放从客户机到服务器方向的传输连接,进入半关闭状态。但此时服务器仍可以向客户端发送数据段;客户端也可接收来自服务器的数据。而且这可能要持续一段时间,直到服务器的数据也全部发送完。
图10-40 TCP传输连接释放的四次握手过程
(3)当客户端收到服务器的ACK数据段后便进入到了FIN WAIT 2状态,进一步等待服务器发出连接释放的数据段。
(4)当服务器发送完全部的数据后,其对应的应用进程也会通知TCP实体释放此方向的TCP传输连接,向客户机发送FIN字段置1,ACK字段置1,ack=m+1(假设此时的数据段序号已变为w)的确认数据段。这时服务器进入LAST ACK(最后确认)状态,等待客户端的确认。
(5)客户端在收到服务器的FIN+ACK数据段后,向服务器发送一个ACK字段置1,ack=w+1,序列号为m+1的数据段,进入到TIME WAIT状态。但此时TCP连接还没有释放,必须等待2MSL时间(RFC 793建议设MSL为2分钟)后,客户端才进入到CLOSED状态,彻底释放了TCP连接。
(6)服务器在收到客户端发来的ACK数据段后,也进入CLOSED状态,彻底释放连接。完成整个TCP传输连接释放过程。
与可以双方同时建立TCP传输连接一样,TCP传输连接关闭也可以由双方同时主动进行(正常情况下都是由一方发送第一个FIN数据段进行主动连接关闭,另一方被动接受连接关闭),如图10-41所示。具体描述如下:
图10-41 同时主动关闭TCP连接的流程
当两端对应的网络应用层进程同时调用CLOSE原语,发送FIN数据段执行关闭命令时,两端均从ESTABLISHED状态转变为FIN WAIT 1状态。任意一方收到对端发来的FIN数据段后,其状态均由FIN WAIT 1转变到CLOSING状态,并发送最后的ACK数据段。当收到最后的ACK数据段后,状态转变化TIME_WAIT,在等待2MSL后进入到CLOSED状态,最终释放整个TCP传输连接。
本文出自 “王达博客” 博客,转载请与作者联系!