TCP/IP笔记之TCP
TCP连接的建立和终止
TCP是一个面向连接的协议。无论哪一方向另一方发送数据之前,都必须现在双方之间建立一条连接。
建立连接需要三次握手(这里有个意外,同时打开需要四次握手)。连接终止协议需要四次握手(同时关闭也只需要四次握手)。
TCP的半关闭:TCP提供了连接的一端在结束它的发送后还能接受来自另一端数据的处理能力。这就是所谓的半关闭。
2MSL状态:如上图,在这个期间,这个socket不能再被使用。
复位报文段:(1)当客户端连到服务端不存在的端口时,服务端发回一个复位报文段;(2)异常终止一个连接,当一socket一端异常终止;(3)检测半打开连接,如果一方已经关闭,另一方不知道,这种状态叫做半打开。
同时打开同时关闭:两个应用程序同时彼此执行主动打开,这是建立连接时用了4次握手。通过这种方式建立的连接需要执行同时关闭(4次握手)。
TCP服务器的设计:当一个新的连接请求到达时,服务器接收这个请求,并调用一个新进程来处理这个新的客户请求。就是说,原来的侦听进程(处于侦听状态)还是一直存在。然后它生成了一个子进程,其状态转换为established,去处理这个请求。如果服务器正处于忙状态,则正在等待连接的请求的一端有一个固定长度的连接队列,然后请求的进程加入连接队列进行等待,直到服务端有空去处理。当队列满了的时候,TCP将不理会传入的SYN,也不发回RST作为应答,因为这是一个软错误。
一个socket接口表示:本地IP地址、本地端口号、远端IP地址和远端端口号。
TCP交互数据流(Telnet)
TCP通信量包括成块数据和交互数据。TCP需要同时出来这两类数据,但使用的处理算法则有所不同。
TCP交互数据的处理,经受时延的确认,通常TCP在接收到数据时并不立即发送ACK;相反,他推迟发送(绝大对数采用的时延为200ms),以便将ACK与需要沿该方向发送的数据一起送。
Nagle算法:在一个Rlogin连接上客户一般每次发送一个字节到服务器,这就产生了一些41字节的分组(1字节数据+20IP头+20TCP头),这些小的分组会增加拥塞出现的可能。一种简单的方法就是Nagle算法,该算法要求一个TCP连接上最多只能一个未被确认的未完成的小分组,在该分组的确认到达之前不能发送其他的小分组。该算法的优越性在于自适应性:确认快,到达快,数据也发送得快。
窗口大小通过:接收方通知发送方自己的缓冲还剩多少,等接收方通知一个0窗口,表示此时发送方不能再发送数据了。因为接收方的应用程序还没有从接收缓冲区里面取走接收的数据,此时缓冲区是满的,不能接收数据。客户端在刚启动时一般通过窗口大小为4096,而服务端一般通过为8192。
TCP的成块数据流
TCP所使用的被称为滑动窗口协议的另一种形式的流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组。由于发送方不必每发送一个分组就停下来等确认(确认也不是一对一的),因此该协议可以加速数据的传输。
滑动窗口(流量控制)是由接收方通告的,称为提出的窗口。我们用三个术语来描述窗口的左右运动:(1)窗口左边沿向右移动称为窗口合拢:这种现象发生在数据被发送和确认时;(2)当窗口右边沿向有移动时称为窗口张开:这种现象发生在另一端接收进程读取已确认的数据并释放了TCP的缓冲区,这样发送方就可以继续发送了;(3)右边沿向左移动叫窗口收缩。不建议这么做。
慢启动(拥塞控制):如果发送方一个开始向网络发送多个报文段,直至到达接收方通告的窗口大小为止。当发送方和接收方处于同一个局域网时,这种方式是可以的。但是如果在发送方和接收方之间存在多个路由器和速率较慢的链路时,就可能出现一些问题。一些中间路由必须缓存分组,并有可能耗尽存储器的空间。慢启动为发送发的TCP增加了另一个窗口:拥塞窗口,记为cwnd,当与另一个网络主机建立TCP连接时,拥塞窗口被初始化为1个报文段(这时发送方只允许发送一个报文段)。每收到一个ACK,拥塞窗口就增加一个报文段(这样发送方可同时发送的报文段,可以一直往上面增加)。发送方取拥塞窗口与通告窗口的最小值作为发送上限。
拥塞窗口是发送方的流量控制,而通告窗口是接收方使用的流量控制。
TCP超时重传
TCP提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确认有可能丢失。TCP通过在发送时设置一个定时器来解决这种问题,当定时器溢出时,没有收到确认,就重传该数据。
对于每个连接,TCP管理了如下四个不同的定时器:(1)重传定时器;(2)坚持定时器;(3)保活定时器;(4)2MSL定时器。
超时重传采用“指数退避”规则。这里里面算法略法则没怎么看。
TCP坚持定时器
TCP通过让接收方指明希望从发送方接收的数据字节数来进行流量控制。在数据被接收方成功接收到以后,接收方会发送一个ACK进行确认,这样发送方就知道接收方已经收到发送的数据报。但是ACK有可能丢失,实际上接收方已经接收到了并且也发送了ACK,但是由于ACK中途丢失,导致发送方接收不到ACK,一直在死等接收方的ACK(因为ACK是表示接收方通告一个非0的窗口,发送方才能发送数据)。而此时,接收方也在等发送方,因为对于接收方来说,它已经通告了一个非0的窗口(非零的窗口表示发送方可以继续发送数据),所以接收方就一直等发送发发数据。造成两方的死等。
解决办法:发送方使用一个坚持定时器来周期性的向接收方查询,以便确定窗口是否增大。
糊涂综合症:接收方可以通告一个小的窗口(而不是一直等到有大的窗口才通告),而发送方也可发送少量数据(而不是等待其他的数据以便发送一个更大的报文段)。
可以采取如下措施避免这种症状:(1)接收方不通告小窗口;(2)发送方在满足下列条件发送数据:可以发送一个满长度的报文段;可以发送至少接收方通告大小一般的报文段;可以发送任何数据并且不希望接收ACK。
TCP保活定时器
如果TCP连接的双方没有向对方发送数据,则在两个TCP模块之间不交换任何信息。就是说我们启动了一个TCP连接之后,离去数天,连接依然保持。这就意味着两个应用进程---客户进程和服务进程---都没有使用应用级的定时器来检测非活动状态,而这种非活动状态可以导致应用进程中的任何一个终止起活动。
保活定时器主要是为服务应用程序提供的。服务器应用程序希望知道客户主机是否崩溃。保活定时器就是试图在服务器端检测到这种半开放的连接。
如果一个给点的连接在2小时之内没有任何动作,服务端定期想客户发送查询请求,客户主机必须处于下面几种状态:(1)客户端依然正常运行,并从服务器可达;(2)客户端崩溃,关闭正在重启;(3)客户端崩溃并已重新启动;(3)客户端正常运行,但从服务器不可达。