TCP内部机制揭秘

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qingyixiaoxia/article/details/80715566

TCP内部机制揭秘

如需转载请注明出处:http://blog.csdn.net/qingyixiaoxia  微信号:qingyixiaoxia

一 TCP和UDP

[一] 传输层概览

 

 

传输层基本特性:

1. 端到端传输:传输层协议部署于网络边缘的终端节点之上,为应用层提供端到端的数据传输服务。传输层提供的服务呈现为SOCKET接口,通过使用SOCKET接口应用层可以不用关心网络交换,路由等细节。

2. 多服务类型:传输层包括UDP和TCP两种服务类型,分别提供:

轻量尽力而为但不可靠的传输服务;

带有复杂可靠性机制的传输服务;

[二] TCP和UDP的对比:

 

[三] TCP特性概览:

 

 

如需转载请注明出处:http://blog.csdn.net/qingyixiaoxia  微信号:qingyixiaoxia

二 TCP的静态特性

[一] TCP包结构

 

 

TCP包结构字段说明:

1) Sequence Number序列号 和 Acknowledgment Number确认号:

Sequence Number序列号为当前传送的TCP包第一个字节在字节流中的偏移;

Acknowledgment确认号为该数据包发送端期待的下一数据包的序列号,即对端发送的下一个数据包首字节在对端发送字节流中的偏移;

2) Window Size接收窗口大小:

该包发送方接收窗口余量。注意,接收窗口大小为65535 * N字节。

其中N是一个单位信息,由选项字段中的Window Scale来指定,且默认为1。

3) CWR/ECE/URG/ACK/PSH/RST/SYN/FIN标志位:

UAPSFR六个标志位指示了TCP数据包的类型。CWR和ECE用于拥塞控制。标志位可以多选。

URG:  携带了紧急数据 (“紧急指针” 有效)

ACK:  携带了确认序号 (“ACK序列号” 有效)

PSH:  携带了用户数据 (“数据” 有效)

SYN:  建链请求

FIN:  断链请求

RST:  复位指示

CWR和ECE用于拥塞控制:

CWR:  拥塞窗口减少 (发送方降速)

ECE:  发送方收到早期拥塞通告

 

4) Options选项字段:

选项字段是一个变长字段,大小从0字节 - 40字节按需变化。常用的选项字段如下述:

MSS:Max Segment Size 最大段大小。用于告诉对端本端期望的最大报文大小。

WSOPT:Window Scale Option窗日缩放因子。用于控制滑动窗口的大小(滑动窗口大小是65535的WSPOT个倍乘数)。

SACK-Permitted:发送者支持SACK选项。

SACK:接收到乱序数据,用于确认。

 

[二] TCP端口号

 

 

TCP端口号说明:

传输层端口号,目的时将一对一的端到端,变成多对多的“点到点”。IP层是端到端的,而传输是每个端上最多65535个点到点的。是对唯一的网卡的复用和解复用。

 

[三] TCP字节流

 

 

关于TCP字节流的说明:

1. 字节流VS数据报:

TCP面向字节流传输: TCP有发送buffer和接收buffer。应用层请求发送的数据不断放在TCP Socket发送buffer中,形成发送字节流。TCP对发送buffer 中的字节流做分段组包,并给与序号,之后递交给IP发送。数据到达接收端后,TCP将应用数据不断放入接收buffer,形成接收字节流。TCP对数据的发送和接收,均未对原始数据的“边界”做处理,而是视所有数据为一个源源不断的字节流。

UDP面向数据报传输: 应用层传来的数据,不予分段,直接交给IP发送。分段和重组的工作由IP完成。UDP发送端发送多大的数据,UDP接收端便一次性接收多大的数据。TCP对发送字节编号:编号变化区间为0 到 - 1。当SEQ到达- 1时,会重新从0开始编号。数据报的SEQ值:是本报文中携带的第一个数据字节在TCP发送字节流中的编号。

2. ACK的SEQ值:是发送端期待接收的下一报文的SEQ值,也即下一报文中第一个字节在对端发送流中的编号。

 

[四] TCP发送缓存和接收缓存

 

 

关于TCP接收缓存和发送缓存的说明:

1.  Overall:数据被物理层接收后,每经过一层协议,剥离对应的头部,并将载荷递交给上层协议处理。

2.  每个TCP Socket有自己的send buffer和recv buffer:

接收数据时:TCP协议栈根据端口号,将收到的数据解复用到对应的Socket,并将载荷存入对应的recv Buffer。

发送数据时:TCP协议栈根据端口号,将发送数据存入对应Socket的send buffer,之后被TCP打包形成发送报文,并复用到IP进行发送。

 

[四] TCP发送窗口和接收窗口

 

 

关于TCP接收窗口和发送窗口的说明:

1. 关于发送窗口的说明:

1)send window的大小:发送窗口的大小,由对端数据报携带的rwnd反馈和拥塞控制窗口cwnd综合决定:发送方窗口 = Min [ rwind, cwind ]。

2)发送窗口的滑动:当收到一个ACK,若携带的ACK位置之前的数据均已被确认,则窗口base滑动向此SEQ所指位置。也既发送窗口的base指向最后一个已发送但未确认的字节。

3)发送时,能发送多少字节,取决于两个因素:第一,本端发送窗口;第二,对端接收窗口余量。发送时,若因发送窗口满,或者因为对端接收窗口余量为零,应用层的待发送的数据将被缓存。

 

2. 关于接收窗口的说明:

1)接收窗口的大小:被应用所控制,应用可以通过SOCKET的setsockopt()调节接收窗口和接收buffer的初始大小。默认的初始值由TCP根据本端软硬件水平设置。

2)接收窗口的滑动:当收到一个数据包,若此包SEQ之前的数据均已收到,则接收窗口的base滑动向“SEQ + 报文大小”。也既接收窗口的base指向最后一个确认完毕字节的下一个字节。

3)当接收端接收窗口为零时,发端会定时发送一字节的wnd查询包,以便当接收端recv window有空闲字节可用时,发端可以及时知晓;

 

如需转载请注明出处:http://blog.csdn.net/qingyixiaoxia  微信号:qingyixiaoxia

三 TCP的动态特性

[一] 面向连接

 

关于建立连接的说明:

Server端的SYN消息中携带了ACK。所以其实三次握手是:

1. Client -> Server:SYN

2. Server -> Client:ACK

3. Server -> Client:SYN

4. Client -> Server:ACK

其中2. 和3. 合并成了一条消息。

 

 

 

关于断开连接的说明:

1. TCP有两种断开连接的方式:FIN优雅断链;RST粗暴断链;

2. 通过FIN优雅的断链:Why三次握手,但是四次挥手?

TCP通过FIN断开链接过程物理意义如下:

S1: 主动端请求断开连接;

S2: 被动端同意;

S3: 被动端发送缓存的待发数据;

S4: 被动端断开连接;

S5: 主动端同意;

由此可见,如果四次挥手合并为三次挥手,被动端就失去了发送缓存数据的机会。总而言之,四次挥手是为了"优雅的"断开连接。

3. 通过RST粗暴的断链,步骤如下:

S1: 主动端直接用socket.close;

S2: 主动端清空所有缓存数据;

S3: 主动端发送RST复位消息并关闭连接;

S4: 被动端收到RST复位消息,直接清空所有缓存数据并关闭连接

 

[二] 确认机制

 

 

关于确认机制的说明:

TCP实践中,每个TCP数据包的ACK标识总是1,ACK Seq也总是携带着某个序列号。无论携带的序列号是不是已经被确认了百八十遍了。TCP永远不会浪费ACK Seq。

[三] 选择性重传

 

 

关于选择性重传的说明:

TCP协议提供可靠数据传输服务。为保证数据传输的正确性,TCP重传其认为已丢失的包。

TCP根据接收端返回至发送端的一系列确认信息来判断是否出现丢包。当数据段或确认信息丢失,TCP启动重传操作来重传尚未确认的数据。

1. TCP拥有两套独立机制来完成重传:

其一,基于时间,也即超时重传;

其二,基于SACK,也即选择确认。当TCP发现”空缺”时,发起重传来填补空缺;

1. TCP并不对每个到来的数据包都返回ACK,利用TCP的累积ACK字段。累积确认可以允许TCP延迟一段时间发送ACK,以便将ACR和相同方向上需要传的数据结合发送。但是注意TCP不能任意时长地延迟ACK,避免对方会误认为数据丢失而进一步出现不必要的重传。

2. TCP超时重传时间:

超时重传无外乎通过一个定时器来为发送出去的数据包计时,当ACK接收超时时发起重传。关键是重传超时时间RTO,这个东东怎么计算?TCP有算法来测算此RTT时间。该时间取值的目标是保证对网络资源最小的浪费。

RTO测算算法有若干种,例如:

RFC793(TRANSMISSION CONTROL PROTOCOL)的算法;

RFC6298(Computing TCP's Retransmission Timer)的算法;(linux采用)

3. RTT测算算法 - RFC793(TRANSMISSION CONTROL PROTOCOL)的算法:

[背书内容]

Step1:首先计算一个平滑的RTT称置为SRTT:

SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)

其中,alpha是一个平滑因子,取值为.8或者.9。在物理意义上,alpha体现了在计算最新RTT时,历史RTT和最新一次的往返时间各自的加权分配。

Step2:基于SRTT,计算RTO:

RTO = min[UBOUND, max[LBOUND,(BETA * SRTT) ]

其中:UBOUND是最大值,一般情况下为120s。LBOUND是最小重传值,一般情况下为1s。Beta取值为1.3 ~ 2.0。

4. RTT测算算法 - RFC6298(Computing TCP's Retransmission Timer)的算法:

[背书内容]

Step1:第一次RTO的计算方法:

SRTT  <-  R

RTTVAR  <-  R/2

RTO  <-  SRTT + max (G, K * RTTVAR)

Step1:后续的RTO计算方法:

RTTVAR  <-  (1 - beta) * RTTVAR + beta * |SRTT - R'|

SRTT  <-  (1 - alpha) * SRTT + alpha * R'  

RTO  <-  SRTT + max (G, 4*RTTVAR)

 

[四] 流量控制

关于流量控制的说明:

1. 流量控制的目标:发端的发送buffer和接收端的接收buffer就发送速度协商一致,避免发送的太快而导致接收端buffer爆掉。

2. 流量控制的方法概述:通过接收buffer反馈完成流量控制。发送端将本端的Socket接收Buffer的剩余空间信息放在TCP数据包的“接收窗口”字段中。接收端根据对方的”接收窗口”信息,决定接下来可以发送的数据量。

3. 零窗口探测报文段: 为了避免收到零窗口报文后,因为丢包等原因无法获知对方已经有新窗口空间可用。当TCP连接的一方收到对方的零窗口通知时就启动持续计时器。若持续计时器设置的时间到期,就发送一个仅仅有一字节数据的零窗口探测报文段,而零探测报文的接收方则会给出新的窗口值。而且TCP规定,即使接收窗口已经满载,也必须接收以下几种报文段:零窗口探测报文段、确认报文段,携带紧急数据的报文段。

4. 糊涂窗口综合征和Nagle算法 [ 背书内容,用于复习相关知识 ]

1) TCP接收方的缓存已满,而交互式的应用进程一次可能只从接收缓存中读取1字节,这样就使接收缓存空间仅腾出1字节。然后向发送方发送确认,并把窗口设置为1个字节。然后,发送方又发来1个字节的数据,接收方发回确认,仍然将窗口设置为1个字节。这样,网络的效率很低。此问题成为糊涂窗口综合征。

要解决糊涂窗口综合征问题:其一,可以从接收方着手,接收方等缓存空间足够大时再向发送方通报新的rwnd数值;其二,可以从发送方着手,避免发送方发送过小的报文。

2) Angle算法:Angle算法为了解决上述糊涂窗口综合征而生。其概要过程如下:

发送方把第一个数据字节发送出去,把后面到达的数据字节缓存起来。当发送方接收对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段再发送出去,同时继续对随后到达的数据进行缓存。只有在收到对前一个报文段的确认后,才继续发送下一个报文段。Nagle算法还规定:当到达的数据已达到发送窗口大小的一半或已经达到报文段的最大长度时,就可立即发送一个报文段。

[五] 拥塞控制

 

 

关于拥塞控制的说明:

1. 什么是网络拥塞:发送端到接收端的漫长路径中,如果中间有某个或者某几个路由器出现了缓存溢出现象,这种现象称为网络拥塞。当网络出现拥塞,所有途径拥塞点的数据包都面临丢包的危险。如果此时各个终端不仅不降速,而且因为丢包而且重传了更多的数据包进入网络,那么网络拥塞的程度只会恶化。为了避免这种状况,TCP提出了拥塞算法。

2. 拥塞控制总体思路:当拥塞状况出现或将要出现时,减缓TCP发送端的发送速率;若拥塞情况有所缓解,可以检测和使用新的可用带宽。RFC2581(TCP Congestion Control protocol)定义了拥塞控制的四个算法:

  慢启动(Slow-start);

  拥塞避免(Congestion Avoidance);

  快重传(Fast Restrangsmit);

  快恢复(Fast Recovery);

注意,具体的实现中,TCP拥塞控制算法有多个版本,例如Tahoe版本,TCP Reno版本(所谓标准版本),Linux版本和Windows版本也各有其差异。后续的总结均基于 RFC5681给出的算法(TCP Congestion Control Protocol)进行。

 

[ 以下内容系背书,用于复习相关知识 ]

3. 慢启动

 

1) 初值:在连接建立之初以及发生超时时,需要执行慢启动操作。TCP以发送一定数目的数据段开始慢启动(在SYN交换之后),称为初始窗口。IW的初始值最典型的设为一个MSS(SYN阶段交换来的最大报文段)。IW的值根据FC5681也可以设置为其他数值,如下:

IW=2*(SMSS)且小于等于2个数据段(当SMSS=2190字节)

IW=3*(SMSS)且小于等于3个数据段(当2190> SMSS=1095字节)

IW=4*(SMSS)且小于等于4个数据段(其他)

2) 指数增长:慢启动的设计含义,是让TCP快速探测可用的网络资源。在此阶段cwnd是以指数快速增长的。慢启动阶段,每接收到一个ACK响应,cwnd如下增长:

CWnd_t+1 = CWnd_t + min(N, SMSS)    (其中N被成功ACK的发送字节数)

推演一下,在接收到第一个数据段的ACK后,cwnd值会增加到2,接着会发送两个数据段。如果成功收到相应的新的ACK, CWnd会由2变4,由4变8,以此类推,也即cwnd会以2的指数增长。

3) 慢启动阑值:ssthresh称慢启动阈值,此阈值是慢启动和拥塞避免之间的界限:

若cwnd<ssthresh,TCP执行慢启动;

若cwnd> ssthresh,TCP执行拥塞避免;

慢启动阈值的设计含义是:当cwnd到达ssthresh而未发生丢包时,意味这还能更快的发送数据。但是如果继续以慢启动阶段指数级增长发生速率,可能导致占用太多网络资源,使得网络快速进入拥塞状态。但是如果cwnd停留在ssthresh不继续增长了,又很可能白白浪费了网络资源。所以,为了”谨慎的”得到更多的传输资源,TCP设计了了拥塞避免算法。

慢启动阑值的用法:TCP建链之初,ssthresh被设置为一个比较大的数值,进入慢启动阶段后,TCP的cwnd指数增长,直至到达sshresh或者发生丢包:

------ 如果TCP cwnd无丢包的达到ssthresh,这虽然预示着可能有更多的网络资源可用,此时TCP谨慎的进入拥塞避免阶段,开始以慢动作去探测更多可利用的网络资源。

------ 如果TCP cwnd在到达ssthresh前发生了丢包,那么会把ssthresh = ssthresh/2,cwnd置为初值,并重新进入慢启动阶段;

 

4. 拥塞避免

 

1) 一旦慢启动阶段cwnd达到慢启动阈值,TCP进人拥塞避免阶段,开始以慢动作去探测更多可利用的网络资源。cwnd结束指数增长,开始随时间线性增长。

在拥塞避免阶段,每接收一个新的ACK, CWnd会做以下更新:

CWnd_t+1 = CWnd_t + SMSS * SMSS/CWnd_t

也即,每次收到一个SMSS ACK,CWnd的值增长1/k个SMSS。对比而言,在慢启动阶段,每次收到一个SMSS ACK,CWnd增长一个SMSS。

 

5. 拥塞探测:

 

1) TCP基于上图所示的”包守恒”来探测是否出现拥塞。如上图所示,发送方发送的数据包经上通道传输给接收方,接收方的ACK包经过下通道传给发送方。在高效传输的稳定状态下,上下通道中均不会丢包,也不会有较大传输间隔,发送包和ACK确认包将完美的有节奏的一一对应。而一旦发生丢包,这一完美图景将被击碎:

要么丢包,导致 发送包数目!=ACK确认包数目;

要么延迟,导致 ACK确认姗姗来迟;

TCP正是基于上述两点来判定网络发生了拥塞。一旦探测到拥塞,则重新进入慢启动.

2) 当探测到拥塞时,TCP会做如下的事情:

其一,设置ssthresh = MAX(cwnd/2, 2*SMSS);

其二,设置Cwnd重新变为初始值;

其三,TCP链接重新进入慢启动阶段:

3) 注意注意,TCP拥塞控制算法假设由比特错误导致包丢失的概率很小,因此有丢包发生就表明从源端到目的端必有某处出现了拥塞。实际上,在不同的网络中,丢包的原因也各不相同,不一定是网络拥塞引起丢包。比如在无线网络中,可能因为bit错误引发丢包,那么TCP的拥塞控制机制使得无线网中即使没有拥塞TCP传输也会变慢。

 

6. 快重传 & 快恢复

1) 当收到3个相同的ACK,此时TCP判定数据包发生丢失,这种状况下,TCP会进行快速重传和快恢复,快速重传和快速恢复做的事情有:
A. 把ssthresh更新为 cwnd/2;
B. 然后把cwnd设置为 ssthresh + 3*SMSS;
C. 重新进入拥塞避免阶段;

D. 每接收一个重复ACK, cwnd值暂时增加1 SMSS

E. 当接收到一个好的ACK,将cwnd重设为ssthresh

以上A,B,C三步构成了快重传算法,

以上D和E构成了快速恢复算法。

猜你喜欢

转载自blog.csdn.net/qingyixiaoxia/article/details/80715566