一.TCP服务的特点
传输层协议主要有两个:TCP 协议和 UDP协议。TCP 协议相对于UDP协议的特点是:面向连接、字节流和可靠传输。
使用TCP协议通信的双方必须先建立连接,然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上数据的传输。TCP 连接是全双工的,即双方的数据读写可以通过一个连接进行。完成数据交换之后,通信双方都必须断开连接以释放系统资源。
TCP协议的这种连接是一对一的,所以基于广播和多播(目标是多个主机地址)的应用程序不能使用 TCP 服务。而无连接协议 UDP则非常适合于广播和多播。
TCP 模块先将这些数据放入 TCP 发送缓冲区中。当TCP 模块真正开始发送数据时,发送缓冲区中这些等待发送的数据可能被封装成一个或多个TCP报文段发出。因此,TCP模块发送出的TCP报文段的个数和应用程序执行的写操作次数之间没有固定的数量关系。
当接收端收到一个或多个TCP报文段后,TCP模块将它们携带的应用程序数据按照TCP报文段的序号(见后文)依次放人TCP接收缓冲区中,并通知应用程序读取数据。接收端应用程序可以一次性将 TCP接收缓冲区中的数据全部读出,也可以分多次读取,这取决于用户指定的应用程序读缓冲区的大小。因此,应用程序执行的读操作次数和TCP 模块接收到的TCP报文段个数之间也没有固定的数量关系。
综上所述,发送端执行的写操作次数和接收端执行的读操作次数之间没有任何数量关系,这就易字节流的概念:应用程序对数据的发送和接收是没有边界限制的。UDP则不然。发送端应用程序每执行一次写操作,UDP模块就将其封装成一个UDP 数据报并发送之。接收端必须及时针对每一个 UDP 数据报执行读操作(通过 recvfrom 系统调用),否则就会丢包(这经常发生在较慢的服务器上)。并且,如果用户没有指定足够的应用程序缓冲区来读取UDP 数据,则 UDP数据将被截断。
下图显示了TCP字节流服务和 UDP 数据报服务的上述区别。两图中省略了传输层以下的通信细节。
TCP传输是可靠的。首先,TCP协议采用发送应答机制,即发送端发送的每个TCP报文段都必须得到接收方的应答,才认为这个TCP报文段传输成功。其次,TCP协议采用超时重传机制,发送端在发送出一个 TCP 报文段之后启动定时器,如果在定时时间内未收到应答,它将重发该报文段。最后,因为TCP 报文段最终是以 IP 数据报发送的,而IP 数据报到达接收端可能乱序、重复,所以TCP协议还会对接收到的TCP 报文段重排、整理,再交付给应用层。UDP 协议则和P协议一样,提供不可靠服务。它们都需要上层协议来处理数据确认和超时重传。
二.TCP状态转移
1.TCP连接的任意一段在任意时刻都处于某种状态,可以通过netstat命令查看。
2.状态转换
我们先讨论服务器的典型状态转移过程,此时我们说的连接状态都是指该连接的服务器端的状态。
服务器通过listen 系统调用(见第5章)进人LISTEN 状态,被动等待客户端连接,因此执行的是所谓的被动打开。服务器一旦监听到某个连接请求(收到同步报文段),就将该连接放入内核等待队列中,并向客户端发送带SYN标志的确认报文段。此时该连接处于SYN_RCVD状态。如果服务器成功地接收到客户端发送同的确认报文段,则该连接转移到 ESTABLISHED 状态。ESTABLISHED 状态是连接双方能够进行双向数据传输的
状态。
当客户端主动关闭连接时(通过 close 或 shutdown 系统调用向服务器发送结束报文段),
服务器通过返回确认报文段使连接进人CLOSE WAIT状态。这个状态的含义很明确:筝待服务器应用程序关闭连接。通常,服务器检测到客户端关附连接后,也企立即纷客户端发送一个结来报文段来关闭连接。这将使连接转移到 LAST ACK状态,以等待客户端对绡束报文段的最后一次确认。一旦确认完成,连接就彻底关闭了。
下面讨论客户端的典型状态转移过程,此时我们说的连接状态都是指该连接的然户端的状态。
客户端通过 connect 系统测用(见第5章)上动与服务器建立连接。connect 系统测用首先给服务器发送一个同必报义段,使连接转移到 SYN SENT 状态。此后、connect 系统测用可能因为如下两个原因返回:
1. 如果conmcct连接的目标端口不存在(未被任何进程监听),或者该端口仍被处于TIME WAIT 状态的连接所占用(见后文),则服务器将给客户端发送一个复位报文段,connect 调用失败。
2.如果目标满口存在,但conncct在超时时间内未收到服务器的确认报文段,则 connect
调用失败
connect调用失败将使连接立即返回到初始的 CLOSED 状态。如果客户端成功收到服务器的同步报文段和确认,则 conncct 调用成功返回,连接转移至 ESTABLISHED状态。
当客户端执行主动关闭时,它将向服务器发送一个结束报文段,同时连接进入FIN WAIT_1状态。若此时客户端收到服务器专门用于确认目的的确认报文段(比如图3-6中的TCP报文段S),则连接转移至FIN_WAIT_2状态。当客户端处于FIN_WAIT_2状态时,服务器处于CLOSE_WAIT状态,这一对状态是可能发生半关闭的状态。此时如果服务器也关闭连接(发送结束报文段),则客户端将给予确认并进人 TIME_WAIT 状态。
下图还给出了客户猫从FIN_WAIT_1状态直接进人 TIME WAIT状态的一条线路(不经过FIN_WAIT_2状态?前提是处于 FIN_WAIT_I状态的服务器直接收到带确认信息的结束报文段(而不是先收到确认报文段,再收到结束报文段)。这种情况对应于图3-6中的服务
器不发送 TCP报文段 5.
前面说过,处于FIN_WAIT_2状态的客户端优要等待服务器发送结束报文段,才能转移至 TIME WAIT 状态,否则它将一直停留在这个状态。如果不是为了在半关闭状态下继续接收数据,连接长时间地停留在 FIN_WAIT_2状态并无益处。连接停留在FIN_WAIT_2状态的情况可能发生在:客户端执行半关闭后,未等服务器关闭连接就强行退出了。此时客户端连接由内核来接管,称之为孤儿连接(和孤儿进程类似)。
三.TIME_WAIT状态
TIME_WAIT状态存在的原因:
1.可靠的终止TCP连接
2.保证延迟到来的TCP报文段有足够的时间被识别丢弃
(
- 在断开连接的过程中,被断开方需要发送给主动断开方FIN报文,来说明被动方要断开连接,主动断开方收到FIN后需要发送确认ACK给被动断开方。若没有ACK被弄丢或者延迟,被动方没有收到ACK 会重复发送FIN,需要进行确认,但若没有TIME_WAIT状态,没有确认,被断开一方不会被注销
- 客户端给服务器发一个报文,报文发出去后,服务器端断开,报文若延迟,需要有TIME_WAIT来收取这些属于自己的延迟报文。
)