[计算机网络-传输层] 面向连接的传输:TCP

参考:http://blog.csdn.net/macdroid/article/details/49070185

在学习TCP之前我们先来看一下可靠数据传输需要提供什么样的机制:

·差错检测机制:检测数据包是否出现比特差错

·反馈机制:接收端对接收到的数据包的反馈

·序列号机制:解决冗余数据包问题

·定时器机制:解决丢包问题

·重传机制:解决数据包出错或丢失问题

下面就来介绍一个典型的可靠数据传输TCP:

TCP具有以下特点:

·点到点:
从一个发送方到一个接收方。连接状态与端系统有关,不为路由器所知。

·可靠、有序的字节流:
传输的数据没有“报文边界”

·流水线型的协议:
TCP拥塞和流量控制设置滑动窗口协议

·具有发送和接收缓冲区

·全双工数据:
同一连接上的允许双向数据流(MSS: 最大报文段长度,MTU:最大传输单元)

·面向连接:
在进行数据交换前,初始化发送方与接收方状态,进行握手(交换控制信息)

·流量控制:
发送方不能淹没接收方

·拥塞控制:
抑止发送方速率来防止过分占用网络资源

下图是TCP报文段的结构

 

由此可看出TCP首部的长度最少为20字节,因为上表中的“选项”通常是没有的。

TCP的可靠传输机制主要靠以下几个方面:

1.报文确认

接收方对于正确接收到的来自发送方的报文段要给予确认返回报文。该报文中的首部ACK指向接收方期待下一个开始接收的字节。

2.超时重传

当发送方发送报文之后,会启动一个倒数计时器(重传超时间隔),计时器为零时,就认为报文可能在网络中丢失,需要重传报文。

那么这个重传超时间隔的值要设为多少呢?

首先,这个值必须大于TCP连接的往返时延(RTT)。

TCP采用的是自适应的方法。设SampleRTT为样本RTT,就是从某报文被发出(即交给IP)到对该报文段的确认被收到之间的时间量。
在任意时刻只为一个已发送但未被确认的报文段估测量,并且仅为传输一次的报文段测量SampleRTT。
可是SampleRTT的值会因为网络的拥塞情况而不段的变化,所以需要一个均值EstimatedRTT:

SampleRTT = (1-a) * EstimatedRTT + a * SampleRTTs

RFC 2988中给出a参考值是0.125。从统计学观点来说,这种平均被称为指数加权移动平均

另外,测量RTT的变化也是有意义的。所以RFC 2988定义了RTT偏差DevRTT。

DevRTT = (1-b) * DevRTT + b * |SampleRTT - EstimatedRTT|

超时间隔应该是等于大于均值的,而超过的均值的范围值可以利用DevRTT。所以超时间间隔的公式就为:

TimeoutInterval = EstimatedRTT + 4 * DevRTT

3.快速重传

当发送端收到3个冗余ACK时就立即重传,而不必要等到定时器超时。

4.差错恢复

在了解TCP的差错恢复机制之前先要介绍下面两种协议:

·回退N步(GBN协议)

·选择重传(SR协议)

GBN(也叫滑动窗口协议):

send_base是基序号,指示最早的未确认分组的序号。 nextseqnum是下一个序号,指示最小的下一个待发送分组的序号。window size就是窗口大小。

每当收到ACK时,send_base指针就会变化,整个窗口就会前移。收到一个ACK时仍有未被确认分组,则计时器被重新启动。
如果出现超时,发送方将重传所有已发送但未确认的分组。
在GBN协议中,接收方会丢弃所有失序的分组。即使前面在失序分组前已经有好几个分组正确到达了。

回退N步示例:

SR:

一个单分组的差错或失序就可能引起GBN重传大量分组,许多分组根本没有必要重传。所以,选择重传协议通过让发送方仅重传它怀疑在接收方出错(即丢失或受损)的分组而避免来不必要的重传。

SR协议中:
发送方的中的每个分组必须拥有自己的逻辑定时器,因为超时后只能发送一个分组。可以使用单个硬件定时器模拟多个逻辑定时器的操作。
接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存,直到一批分组按序接收成功了则交付上层。

由于接收方接收了分组就发送ACK,移动自身的接收窗口,而发送方有可能因为ACK丢失等原因迟迟没收到确认报文以至于窗口不移动。所以,对于SR协议而言,这就意味着发送方和接收方的窗口并不总是一致。

选择重传示例:

TCP的差错恢复机制为选择确认。

它允许TCP接收方有选择地确认失序报文段,而不是累积地确认最后一个正确接收的有序报文段。当将该机制与选择重传机制结合起来使用(即跳过那些已被接收方选择性地确认过的报文段的重传)时,TCP看起来像我们通常的SR协议。因此TCP的差错恢复机制可以被划分为GBN协议与选择重传协议的混合体

下面来详细解释一下TCP的有限状态机

TCP_CLOSE:关闭状态,一个新建的TCP socket会处于该状态。

TCP_LISTEN:监听状态,一般服务器端套接字在调用Listen系统调用后即处于该状态。

TCP_SYN_SENT:同步信号已经发送状态,这个状态一般是指客户端发送SYN(建立连接的同步)数据包后所处的状态(tcp三次握手的第一个包)。在接收到远端服务器端的应答后,即从该状态进入TCP_ESTABLISHED状态。

TCP_SYN_RECEIVED:同步信号已经接受状态,服务器端在接受到远端客户端SYN数据包后,进行相应的处理(创建通信套接字等),然后发送应答数据包(tcp三次握手的第二个包),并将新创建的通信套接字状态设置为TCP_SYN_RECEIVED,在接受到客户端的应答后,即进入TCP_ESTABLISED状态。

TCP_ESTABLISED:建立连接状态,这是双方进行正常通信所处的状态。

TCP_FIN_WAIT_1:本地发送FIN(用于结束连接的)数据包后即可进入该状态,等待对方的应答。一般一端发送完其所要发送的数据后,即可发送FIN数据包,此时发送通道被关闭,但仍可继续接受远端发送的数据包。在接受到远端发送的对于FIN数据包的应答后,将进入TCP_FIN_WAIT_2状态。

TCP_FIN_WAIT_2:进入该状态表示本地已经接收到远端发送的对于本地之前发送的FIN数据包的应答。进入该状态后,本地仍然可以继续接收远端发送给本地的的数据包。在接收到远端发送的FIN数据包后(表示远端也已经发送完数据),本地将发送一个应答数据包,并进入TCP_TIME_WAIT状态。TCP_TIME_WAIT状态存在的时间被称为2MSL时间,这一方面是为避免本地发送的应答数据包丢失,另一方面避免一个新创建的套接字接收到旧套接字中遗留的数据包。

TCP_TIME_WAIT:该状态被称为2MSL等待状态。如果在此期间接收到远端发送的FIN数据包,则表示之前在TCP_FIN_WAIT_2状态发送的ACK应答数据包在传输中丢失或者长时间被延迟,从而造成了远端重新发送了FIN数据包,此时重复ACK应答数据包。一旦2MSL时间到期,则将进入TCP_CLOSED状态,即完成关闭操作。

TCP_CLOSE_WAIT:该状态存在于后关闭的一端。当接收到远端发送的FIN数据包后,本地发送一个ACK应答数据包,并将该套接字状态从TCP_ESTABLISED设置为TCP_CLOSE_WAIT。本地可以继续向远端发送数据包,在发送完所有的数据后,本地将发送一个FIN数据包关闭本地发送通道,并将状态设置为TCP_LAST_ACK状态,等待远端对FIN数据包的应答数据包。

TCP_CLOSING:如果通信双方同时发送FIN数据包,则同时进行关闭操作,则双方将同时进入TCP_CLOSING状态。具体的,本地发送一个FIN数据包以结束本地数据包发送,如果在等待应答期间,接收到远端发送的FIN数据包,则本地将状态设置为TCP_CLOSING状态。在接收到应答后,再继续装入到TCP_CLOSE_WAIT状态。

TCP_LAST_ACK:作为后关闭的一方,在发送FIN数据包后,即进入TCP_LAST_ACK状态。此时等待远端发送应答数据包,在接收到应答数据包后,即完成关闭操作,进入TCP_CLOSE状态。

下面是上述过程的更直观的体现:

TCP三次握手:

步骤:
1.客户端向服务端发送一个特殊的TCP报文段。该报文段不包含应用层数据,但需要把报文段首部的SYN标志位置1。这个报文被称为SYN报文段。除了SYN,还需要加上SEQ字段指示客户端的开始序号。
2.服务端接收到SYN报文之后,就为该TCP连接分配TCP缓存和变量,并向客户端发送允许连接的报文段。该报文段包含SYN和SEQ,意义同上。但还附带一个ACK指示想要收到的下一个字节。该允许连接的报文段有时被称为SYN_ACK报文段。
3.在收到来SYN_ACK报文段后,客户机也要给该连接分配缓存和变量。这时客户端还会向服务端发送另一个报文段,是对SYN_ACK报文段进行确认。因为连接已经成功建立,所以该SYN被置0。

TCP四次挥手:

步骤:
如图所示,客户端应用进程发出一个关闭连接命令。这会引起客户端TCP向服务端进程发送一个特殊的TCP报文段。这个特殊的报文段首部中的FIN比特被置1。当服务接收到该报文段后,就向客户端会送一个确认报文段。这时,TCP连接处于半关闭状态。半关闭指的是客户端已经不能再给服务端发送数据了,但可以接收服务端发过来的数据。数据传送完毕之后,服务端发送其终止报文段,同样FIN被置1。最后客户端对这个服务端的终止报文段进行确认。两台主机的TCP连接成功释放。
注意,如果服务端不需要向客户端传输数据了,那么ack = u + 1的这个两个报文是可以结合为一个的。

【问题1】为什么客户端最后需要等待2MSL呢?

MSL意思是报文段最大生存时间(Maximum Segment Lifetime)。它是任何报文段被丢弃前在网络内的最长时间。因为网络层有限制生存时间字段TTL,所以MSL值是有限的,常用可能会30秒,1分钟,2分钟。

TIME_WAIT确保有足够的时间让对端收到了ACK,如果被动关闭的那方没有收到Ack,就会触发被动端重发Fin,一来一去正好2个MSL

【问题2】如果因为机器故障而导致连接被中断要怎么办?

TCP设有一个保活计时器。服务端每收到一次客户的数据都会重新设置该计时器。计时器到时之后,服务端会主动发送探测报文,连续几个探测报文没反应的话,服务端就会自动关闭。

【问题3】为什么连接的时候是三次握手,关闭的时候却是四次握手?

因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN_ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,"你发的FIN报文我收到了"。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

原文地址:https://www.cnblogs.com/lca1826/p/6599417.html