TCP协议


发布于 2015-12-08 / 44 阅读 / 0 评论 /
TCP协议是TCP/IP网络模型中传输层的一种协议

1.TCP协议特点

TCP主要有以下特点:

(1)基于字节流,无边界

(2)面向连接

(3)可靠传输

(4)缓冲传输

(5)全双工

(6)流量控制

2.TCP报文格式

TCP报文格式如下图所示:

字段说明如下:

2.1.源端口和目的端口

各为16位,源端口号和目的端口号,加上IP首部的源IP地址和目的IP地址唯一确定一个TCP连接。

2.2.序号

32位,表示这个报文段中的第一个数据字节序号。

2.3.确认号

32位,仅当ACK标志为1时有效,确认号表示期望收到的下一个字节的序号。

2.4.头部长度

4位,表示TCP头部所占4字节的多少倍,最多60字节。

2.5.保留位

6位,必须为0。

2.6.共6个标志位

URG:紧急指针有效

ACK:确认序号有效

PSH:接收方应尽快将这个报文段交给应用层

RST:连接重置

SYN:同步序号用来发起一个连接

FIN:表示将要终止一个连接

2.7.窗口

16位,通过窗口大小来达到流量控制。

2.8.校验和

16位,对tcp头与数据进行校验。

2.9.紧急指针

16位,是一个正的偏移量,与序号字段的值相加表示紧急数据最后一个字节的序号。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。

2.10.选项与填充

选项为4字节的整数倍,否则用0填充。最常见的可选字段是最长报文大小MSS(Maximum Segment Size),每个连接方通常都在通信的第一个报文段中指明这个选项。它指明本端所能接收的最大长度的报文段。该选项如果不设置,默认536,

3.TCP三次握手过程

TCP三次握手是TCP连接建立的过程。整个过程如下图所示:

SYN=1表示建立连接,确认号ACK=Seq+1。

有五种状态:

(1)CLOSED:初始状态,客户端socket处于关闭状态。

(2)LISTEN:表示服务器端的某个SOCKET处于监听状态,可以接收连接了。

(3)SYN_RCVD:这个状态表示服务端接收到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本 上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态 时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。

(4)SYN_SENT:这个状态与SYN_RCVD相呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的 [S.] 报文。SYN_SENT状态表示客户端已发送SYN报文。

(5)ESTABLISHED:连接已经建立。

4.TCP四次挥手过程

TCP四次挥手是TCP连接断开的过程。整个过程如下图所示:

FIN=1表示关闭连接,Seq=原Seq+1

主要涉及六种状态:

(1)FIN_WAIT_1

本质上FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。

(2)FIN_WAIT_2

实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方(比如client)要求close连接,但我(server)告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。

(3)CLOSE_WAIT

这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是查看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。

(4)TIME_WAIT状态

主动方保持time_wait状态2MSL时间后,才会彻底关闭回收资源。

设计此状态的原因:首先,我们没有任何机制保证最后的一个ACK能够正常传输;第二,网络上仍然有可能有残余的数据包(wandering duplicates),我们也必须能够正常处理。

假设最后的一个ACK丢失,那么被动关闭一方收不到这最后一个ACK则会重发FIN。此时主动关闭一方必须保持一个有效的(time_wait状态下维持)状态信息,以便可以重发ACK。如果主动关闭的socket不维持这种状态而是进入close状态,那么主动关闭的一方在收到被动关闭方重新发送的FIN时则响应给被动方一个RST。被动方收到这个RST后会认为此次回话出错了。

假设目前连接的通信双方都调用了close(),双方同时进入closed的终结状态,而没有走 time_wait状态。则会出现如下问题:假如现在有一个新的连接建立起来,使用的IP地址与之前的端口完全相同,现在建立的一个连接是之前连接的完全复用,我们还假定之前连接中有数据报残存在网络之中,这样的话现在的连接收到的数据有可能是之前连接的报文。为了防止这一点。TCP不允许新的连接复用time_wait状态下的socket。处于time_wait状态的socket在等待2MSL时间后(之所以是两倍的MSL,是由于MSL是一个数据报在网络中单向发出 到认定丢失的时间,即(Maximum Segment Lifetime)报文最长存活时间,一个数据报有可能在发送途中或是其响应过程中成为残余数据报,确认一个数据报及其响应的丢弃需要两倍的MSL),将会转为closed状态。这就意味着,一个成功建立的连接,必须使得之前网络中残余的数据报都丢失了。

(5)LAST_ACK

这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,即可关闭连接了。

(6)CLOSING

这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的 ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在尝试关闭SOCKET连接。

5.TCP如何保证数据可靠性

TCP保证数据可靠性的机制如下:

(1)应用数据被分割成TCP认为最合适发送的数据块,称为段,传递给IP层。

(2)当TCP发出一个段后,它启动一个定时器,等待目的端接收到这个报文段,如果不能及时收到一个确认,将重发这个报文段。

(3)当TCP收到TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟。

(4)TCP将保持首部和数据的校验和。如果接收到段的校验和有差错,TCP将丢弃这个报文段并且不确认,导致对方超时重传。

(5)TCP承载于IP数据报来传输,IP数据报的到达可能失序,因此TCP报文段也可能失序,TCP将对接收到的数据进行重新排序。

(6)IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。

(7)TCP还能提供流量控制,TCP连接的每一方都有一定大小的缓冲空间。

6.窗口

TCP中有两种窗口:固定窗口和滑动窗口。

6.1.固定窗口

窗口大小为1的时序图如下所示:

窗口的大小是1,即每次只能发送一个数据只有接收方对这个数据进行确认了以后才能发送下一个数据。

如果窗口过小,那么当传输比较大的数据的时候需要不停的对数据进行确认,这个时候就会造成很大的延迟。

如果窗口过大。我们假设发送方一次发送100个数据。但是接收方只能处理50个数据。这样每次都会只对这50个数据进行确认。发送方下一次还是发送100个数据,但是接受方还是只能处理50个数据。这样就避免了不必要的数据来拥塞我们的链路。

所以我们就引入了滑动窗口机制,窗口的大小并不是固定的而是根据我们之间的链路的带宽的大小。

6.2.滑动窗口

滑动窗口通俗来讲就是一种流量控制技术。它本质上是描述接收方的TCP数据报缓冲区大小的数据,发送方根据这个数据来计算自己最多能发送多长的数据,如果发送方收到接收方的窗口大小为0的TCP数据报,那么发送方将停止发送数据,等到接收方发送窗口大小不为0的数据报文的到来。

滑动窗口应用案例如下图所示:

上图中,接收方传递自己的窗口大小给发送端,使其不要发送数据太快。

这里面涉及到一种情况,如果B已经告诉A自己的缓冲区已满,于是A停止发送数据;等一段时间后,B的缓冲区出现了富余,于是发送报文告诉A我的RWND大小为400,但是这个报文不幸丢失了,于是就出现了A等待B的通知 || B等待A发送数据的死锁状态。

为了解决这个问题,TCP引入了持续计时器(Persistence timer)当A收到对方的零窗口通知时,就启动该计时器,时间到则发送一个字节的探测报文,对方会在此时回应自身的接受窗口的大小,如果结果仍为0,则重设持续计时器(更新),继续等待。

滑动窗口相关概念如下:

(1)接收窗口:rwnd,接收方使用的流量控制,预防应用程序发送的数据超过对方的缓冲区。

(2)拥塞窗口:cwnd,发送方使用的流量控制,预防应用程序发送的数据超过网络所能承受的能力。

(3)发送窗口取cwnd和rwnd的最小值。

(4)慢启动阈值:ssthresh

(5)慢启动阶段:cwnd从1开始指数增长到ssthresh。

(6)拥塞避免阶段:cwnd按线性增长,直到拥塞,将cwnd=1、ssthresh减半。

拥塞算法启动过程如下图所示:

上述方法的目的是在拥塞发生时循序减少 主机发送到网络中的分组数,使得发送拥塞的路由器有足够的时间去把队列中积压的分组处理完毕。