TCP协议全称: transmission contril protocol,顾名思义,就是要对数据的传输进行一定的控制。

 TCP协议报头如下:

tcp timestamp 字段解析 tcp数据字段_数据

 

 各字段意义如下:

源端口和目的端口:表示数据从哪个进程来,到哪个进程去。

序号字段:seq,TCP是面向字节流的,所以TCP连接中传送的数据流中每一个字节都编上一个需要。序号字段的值则表示值得是本报文字段所发送的数据的第一个字节的序号。

确认字段:ack,是期望受到对方的下一个报文段的数据的第一个字节的需要。若确认号为n,则表示n-1为止的所有数据都已经正确收到。

数据偏移:表示首部的长度,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。

保留字段:以后用,现在不使用。

URG: 标识紧急指针是否有效
ACK: 标识确认序号是否有效
PSH: 用来提示接收端应用程序立刻将数据从tcp缓冲区读走
RST: 要求重新建立连接. 我们把含有RST标识的报文称为复位报文段
SYN: 请求建立连接. 我们把含有SYN标识的报文称为同步报文段
FIN: 通知对端, 本端即将关闭. 我们把含有FIN标识的报文称为结束报文段
窗口字段:指出了现在允许对方发送的数据量,因为接收方的数据缓存空间是有限的。

检验和:由发送端填充, 检验形式有CRC校验等. 如果接收端校验不通过, 则认为数据有问题. 此处的校验和不光包含TCP首部, 也包含TCP数据部分.

紧急指针:指出本报文段中紧急数据共有多少字节。

选项填充略。

 

TCP连接要解决的问题:

1.使每一方都能知道对方的存在。

2.要允许双方协商一些参数(最大窗口值,是否使用窗口扩大项,时间戳选项等)。

3.要把运输实体资源进行分配(缓存大小,连接表中的项目等)。

 

正常情况下, tcp需要经过三次握手建立连接, 四次挥手断开连接。

其总结就是:

连接建立:

SYN=1,seq=x

SYN=1,ACK=1,seq=y,ack=x+1

ACK=1,seq=x+1,ack=y+1

 

tcp timestamp 字段解析 tcp数据字段_数据_02

 

 

释放连接:

FIN=1,seq=u

ACK=1,seq=v,ack=u+1

FIN=1,ACK=1,seq=w,ack=u+1

ACK=1,seq=u+1,ack=w+1

 

tcp timestamp 字段解析 tcp数据字段_客户端_03

 

 

TCP连接的建立:

第一步:客户端向服务器发送一个连接请求报文段,这个报文段不含应用层数据,SYN=1,另外,客户机会随机选择一个序列号seq=x。

第二步:服务端收到请求报文段以后,如果同意建立连接,就向客户机发回确认,并为该TCP连接分配TCP缓存和变量。在报文段中,SYN=1,ACK=1,ack=x+1,并随机选择一个序列号seq=y。

第三步:客户机收到确认报文段以后,还要向服务器发出确认,并且也要给该连接分配缓存和变量。此时ACK=1,seq=x+1,ack=y+1。此时的报文段可选携带数据。、

 

为什么收到服务端的确认以后,客户端还要进行第三次握手呢?

如果客户端发出的第一个请求报文段没有丢失,而是在某一个网络节点长时间滞留了,导致延误到连接释放以后才到达服务端,这本来是一个失效的报文段,当服务端收到该连接请求报文段以后,就会误以为是客户端发出的新的连接请求,于是就向客户端发出确认报文段,假如不采用三次握手,那么只要服务端确认,连接就建立了,而此时由于客户端并没有发出连接的请求,因此不会理睬服务端的确认,但是服务端却以为新的连接已经建立,并且一直等待客户端发来数据,这样,服务端的资源就被浪费掉了。

而如果是三次握手,此时客户端收到以后,会发送一个复位报文段,虽然此时客户端对服务端的SYN报文段确认ACK了,但是由于发送了RST=1报文段,告诉了服务端它拒绝了该请求。

 

建立连接的第二个SYN作用是什么?

理由同上,我们必须要认为网络连接是不可靠的,如果客户端发送的SYN过了好久才到达服务端,而此时客户端超时重传的SYN已经到了服务端,那么后来的SYN就是无效的,如果不发送第二个SYN查询客户端是否有效的话,服务端就会一直监听这个延迟到达的请求,造成资源的浪费。

 

TCP连接的释放:

第一步:客户端打算关闭连接,就发送一个释放连接报文段,并停止再发送数据,主动关闭TCP连接。该报文段FIN=1,seq=u,它等于前面已经传送国的数据的最后一个字节的序号+1。由于TCP是全双工的,即可以想象一条TCP连接上有俩条数据通路,当发送FIN报文时,这一端就不再发送数据了,也就关闭了其中一条通路,但是对方还可以发送数据。

第二步:服务端收到连接释放的报文段以后发出确认,确认号是ack=u+1,而这报文段自己的序号是seq=v,等于它前面已经传送过的数据的最后一个字节的序号+1.此时,从客户机到服务器这个方向的连接就释放了,TCP属于半关闭状态。此时服务端如果要发送数据,客户端依然要接收。

第三步:当服务器已经没有要向客户端发送的数据了,就通知TCP释放连接,此时发出的FIN=1,seq=w,等于它前面已经传送国的数据的最后一个字节的序号+1。

第四步:客户端收到连接释放报文段后,必须发出确认,在确认报文段中,ACK=1,确认号ack=w+1,序号seq=u+1。此时TCP还没有释放掉,必须要经过时间等待计时器的2MSL后,客户端才进入到连接关闭状态。

 

为什么要四次挥手:

为了确保能够完成传输。

当关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了,但是未必你所有的数据都全部发送给对方了,所以你可以未必会马上关闭SOCKET,你可能还需要发送一些数据给对方以后,再发送FIN报文段给对方来同意现在可以关闭连接了。所以这里服务端的的ACK报文和FIN是分开发送的。

 

关闭连接时最后一个ACK丢失了怎么办:

如果最后一个ACK丢失的话,TCP就会认为它的FIN丢失,进而重发FIN。在客户端收到FIN后,就会设置一个2MSL计数器,从而产生足够的时间等待下一个FIN到来。如果在TIME-WAIT状态有一个新的FIN到达了,客户端就会发送一个ACK,并重新设置2MSL计数器。

 

time_wait状态产生的原因:

1.可靠地实现TCP全双工连接的终止

我们必须要假设网络连接是不可靠的,你无法保证最后发送的ACK报文一定会被对方接收,因此服务端处于LAST_ACK状态的SOCKET会因为超时未收到ACK报文,而重发FIN状态,客户端必须维持这条连接的状态,一边可以重发丢失的ACK,如果主动关闭端不维持TIME_WAIT状态,而是处于CLOSED状态,主动关闭端将会响应一个REST,结果服务端认为发生错误,导致服务端不能正常关闭连接。所以,这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。所以,当客户端等待2MSL(2倍报文最大生存时间)后,没有收到服务端的FIN报文后,他就直到服务端已经收到了ACK报文,所以客户端此时才关闭自己的连接。

2.允许老的重复报文在网络中消逝

为了防止上面提到的“已失效的连接请求报文段”出现在本连接中,A在发送完最后一个ACK报文段以后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。

如果TIME_WAIT状态保持的时间不够长,第一个连接正常终止了,第二个拥有相同元组的连接(建立起一个相同的IP地址和端口之间的TCP连接),而第一个连接的重复报文也到达了,就会干扰第二个连接。因此,TCP必须防止某个连接的重复报文在连接终止以后出现。所以TIME_WAIT时间必须足够长,连接相应方向上的TCP报文要么完全响应完毕,要么被丢弃。

 

如果出现大量TIME_WAIT产生的结果和解决办法:

由于本地端口数量有限,如果系统中有多个SOCKET处于TIME_WAIT,那么新建连接的本地端口就会缺乏。

产生大量TIME_WAIT的解决办法:

改为长连接

增大端口可用范围

 

如何理解TCP是可靠传输


 

TCP的任务在IP层是不可靠的,但是在IP层之上建立了一种可靠的数据传输服务。TCP使用了校验、序号、确认、重传等机制来达到这个目的。

1.校验

TCP的校验和UDP是一样的。

2.序号

TCP首部的序号字段用来保证数据是有序的提交给应用层。TCP把数据看成是一个无结构但是有序的字节流,而序号是建立在传送的字节流上,而不是报文段上。

TCP连接中传送的数据流中的每一个字节都边上一个序号,序号的字段的值则指的是本报文段所发送的数据的第一个字节的序号。比如,A和B之间建立了一个TCP连接,A的发送缓冲区一共有10个字节,序号从0开始编号,第一个报文包含第0-2个字节,则该TCP报文段的序号是0,第二个报文段的序号是3。

3.确认

TCP首部的确认号是期望收到对方的下一个报文段的数据的第一个字节的序号。发送方缓冲区会储存那些已经发送但未收到确认的报文段,以便在需要的时候重传。

TCP默认使用累计确认,及TCP只确认数据流中到第一个丢失字节为止的字节。例如,B收到了A发送的0-2,6-7报文段,但是没有收到3-5报文段,此时B仍在等待字节3(和后面的字节)。一起,B到A的下一个报文段将ack置为3。

4.重传

有俩种情况导致TCP对报文段进行重传:超时和冗余ACK

1.超时

TCP每收到一个报文段,就对这个报文段设置一次计时器,只要计时器设置的重传时间到期还没有收到确认,就要重传这一报文段。

TCP采用一种自适应算法,通过每一次报文段发出的时间和收到确认的时间得出RTO。

2.冗余ACK

超时重传存在的一个问题就是超时周期往往太长,而冗余ACK就是再次确认某个报文段的ACK,而发送方先前已经收到过该报文段的确认。如,发送方发送了序号未:1,2,3,4,5的报文段,但是2丢失,因此3,4,5成了失序报文段。TCP规定每当比期望序号大的失序报文段到达时,发送一个冗余ACK,指明下一个期待的字节的序号。在这个例子中,3,4,5到达B,但不是B期待收到的下一个报文,于是B就发送3个对1号报文段的冗余ACK,表示自己期待收到2号报文段。TCP规定当发送方接收到对同一个报文段的3次冗余ACK时,就可以认为在这个被确认报文段之后的报文段已经丢失。冗余ACK还可以用在拥塞控制中,褶子技术被称为快重传。

 

TCP拥塞控制:

拥塞控制流量控制的区别:

拥塞控制是防止过多的数据注入网络中,这样可以使得网络中的路由器或者链路不至于过载。

流量控制是对点对点的通信量的控制,控制发送端发送数据的速率,以便使接收端来得及接收。

 

为了更好的对传输层进行拥塞控制,因特网建议标准定义了以下四种算法:慢开始,拥塞避免,快重传,快恢复

为了考虑发送方在确定发送报文段的速率时,既要考虑接收方的接收能力,又要从全局考虑不要使网络发生拥塞。因此,TCP协议要求发送方维护以下俩个窗口:

1.接收窗口 rwnd :接收方根据目前接收缓存大小所许诺的最新的窗口值,反映了接收方的容量。由接收方根据其放在报文的首部的窗口字段通知发送方。

2.拥塞窗口 cwnd: 发送方根据自己估算的网络拥塞程度而设置的窗口值,该窗口根据网络的拥塞情况设置大小。

发送窗口的上限值应该取 rwnd 和 cwnd 中较小的一个,即:min[ rwnd , cwnd ]

 

1.慢开始和拥塞避免

tcp timestamp 字段解析 tcp数据字段_数据_04

 

2.快重传和快恢复

 

tcp timestamp 字段解析 tcp数据字段_tcp timestamp 字段解析_05

TCP滑动窗口机制

TCP提供了流量控制服务以消除发送方使接收方缓冲区溢出的可能性,因此可以说流量控制是一个速度匹配服务。TCP提供了一一种基于滑动窗口协议的流量控制。

但是该滑动窗口机制位于传输层,与数据链路层不同在于:传输层定义了端到端之间的流量控制,数据链路层定义了俩个中间的相邻节点的流量控制,数据链路层的滑动窗口大小不能动态变化,传输层可以动态变化。

在TCP中,窗口的大小是在TCP三次握手后协定的,并且窗口的大小并不是固定的,而是会随着网络的情况进行调整,其字段位于rwnd。

1. “窗口”对应的是一段可以被发送者发送的字节序列,其连续的范围称之为“窗口”;

2. “滑动”则是指这段“允许发送的范围”是可以随着发送的过程而变化的,方式就是按顺序“滑动”。

        TCP协议的两端分别为发送者A和接收者B,由于是全双工协议,因此A和B应该分别维护着一个独立的发送缓冲区和接收缓冲区,由于对等性(A发B收和B发A收),我们以A发送B接收的情况作为例子;

  •                 发送窗口是发送缓存中的一部分,是可以被TCP协议发送的那部分,其实应用层需要发送的所有数据都被放进了发送者的发送缓冲区;

  •               发送窗口中相关的有四个概念:已发送并收到确认的数据(不再发送窗口和发送缓冲区之内)、已发送但未收到确认的数据(位于发送窗口之中)、允许发送但尚未发送的数据以及发送窗口外发送缓冲区内暂时不允许发送的数据

  •                每次成功发送数据之后,发送窗口就会在发送缓冲区中按顺序移动,将 新的数据包含到窗口中准备发送;

tcp timestamp 字段解析 tcp数据字段_tcp timestamp 字段解析_06

 

从流量控制的角度来看更容易理解:

每次成功发送数据之后,发送窗口就会在发送缓冲区中按顺序移动,将新的数据包含到窗口中准备发送;要是接收方传递信息给发送方,使其不要发送数据太快,是一种端到端的控制。主要的方式就是返回的ACK中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送:

 

tcp timestamp 字段解析 tcp数据字段_tcp timestamp 字段解析_07

 TCP与UDP区别总结:

    TCP的主要特点是:
        面向连接。
        每一条TCP连接只能是点对点的(一对一)。
        提供可靠交付的服务(无差错,不丢失,不重复,且按序到达)(校验和、重传控制、序号标识、滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。)。
        提供全双工通信。
        面向字节流。
    UDP的主要特点是:
        无连接。
        尽最大努力交付(不保证可靠交付)。
        面向报文。
        无拥塞控制。
        支持一对一、一对多、多对一和多对多的交互通信。
        首部开销小(只有四个字段:源端口、目的端口、长度、检验和)。

采用TCP,一旦发生丢包,TCP会将后续的包缓存起来,等前面的包重传并接收到后再继续发送,延时会越来越大。

UDP对实时性要求较为严格的情况下,采用自定义重传机制,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成影响。