TCP传输控制协议分析

版权声明:<--本博客所有内容均为个人在学习工作中的总结、摘录等-- --转载请注明出处-- --如有侵权请联系删除--> https://blog.csdn.net/qq_42196196/article/details/83865752

简介

        TCP(Transmission Control Protocol)即传输控制协议。是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,另一个重要的传输协议。在因特网协议族中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。
主要特点:1.面向连接 2.一对一传输 3.可靠交付 4.只支持全双工通信 5.面向字节流 6.比UDP协议首部开销大

封包格式及各字段分析

封包格式

字段分析

(1)源端口:占2字节、标明源端口
(2)目的端口:占2字节、标明目的端口
(3)序号:占4字节、序号范围是[0,2^32-1,(即4294967296)个序号。序号增加到2^32-1后,下一个序号就又回到0。也就是说,序号使用mod2^32运算。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则指的是本报文段所发送的数据的第一个字节的序号。例如,一报文段的序号字段值是301,而携带的数据共有100字节。这就表明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值应为401。这个字段的名称也叫做“报文段序号"
(4)确认号:占4字节、是期望收到对方下一个报文段的第一个数据字节的序号。例如,B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节 (序号501~700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。请注意,现在的确认号不是501,也不是700,而是701总之,应当记住若确认号=N,则表明:到序号N-1为止的所有数据都已正确收到。由于序号字段有32位长,可对4GB(即4千兆字节)的数据进行编号。在一般情况下可保证当序号重复使用时,旧序号的数据早已通过网络到达终点了
(5)数据偏移:占4位、它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段实际上是指出TCP报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。但应注意,“数据偏移”的单位是32位(即以4字节长的字为计算单位,不足4字节需要补齐)。由于4位二进制数能够表示的最大十进制数字是15,因此数据偏移的最大值是60字节(15×4字节),这也是TCP首部的最大长度(即选项长度不能超过40字节)。
(6)保留:占6位,保留为今后使用,但目前应置为0。

六个控制位:
(7)紧急URG(Urgent):占一位、当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),而不要按原来的排队顺序来传送。例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行。因此用户从键盘发出中断命令( Contr+C)。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了许多时间。当URG置1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。这时要与首部中紧急指针 (Urgent Pointer )字段配合使用。
(8)确认ACK( Acknowledgment ):占一位、仅当ACK=1时确认号字段才有效。当ACK=0时确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1。
(9)推送PSH(PuSH):占一位、当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP就可以使用推送操作。这时,发送方TCP把PSH置1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。虽然应用程序可以选择推送操作,但推送操作很少使用。
(10)复位RST( Reset ):占一位、当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。RST置1还用来拒绝一个非法的报文段或拒绝打开一个连接。RST也可称为重建位或重置位。
(11)同步SYN( Synchronization ):占一位、在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。因此,SYN置为1就表示这是一个连接请求或连接接受报文。
(12)终止FIN(FINis):占一位、用来释放一个连接。当FN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。

(13)窗口:占2字节、窗口值是[0,2^16-1]之间的整数。窗口指的是发送本报文段的一方的接收窗口(而不是自己的发送窗口)。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。
(14)检验和:占2字节、检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式与UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号),把第5字段中的UDP长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用IPv6,则相应的伪首部也要改变。
(15)紧急指针:占2字节、紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)。因此,紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗口为零时也可发送紧急数据。
(16)选项:长度可变、最长可达40字节。当没有使用“选项“时,TCP的首部长度是20字节。TCP最初只规定了一种选项(最大报文段 MSS),随着互联网的发展,又陆续加了几个选项,如窗口扩大选项,时间戳选项参考[RFC 7323],选择确认(SACK)选项参考[RFC 2018]。

数据包分析

对照报文格式看数据包

TCP的一些特性:

可靠传输的实现

滑动窗口

        TCP的滑动窗口都是以字节为单位
        发送窗口后沿的变化情况有两种可能,1.不动--没有收到新的确认,2.前移--收到了新的确认,但是发送窗口不会向后移,因为不能撤销收到的确认。如图,B的接收窗口32号,33号报文已经到达,但是31号报文没有到,所以接收窗口不能前移。A的发送窗口31-41号报文都已发送出去但是一个都没有确认收到,所以接收窗口也不能前移。
        描述一个发送窗口需要三个指针:P1,P2,P3,三个指针有以下的意义:
小于P1的是已发送并已收到确认的部分
大于P3的是不允许发送的部分
P3-P1=A的发送窗口
P2-P1=已发送尚未收到确认的字节数
P3-P2=允许发送但当前尚未发送的字节数(又称为可用窗口或有效窗口)

超时重传

        TCP采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是报文段的往返时间RTT。TCP保留了RTT的一个加权平均往返时间RTTs(这又称为平滑的往返时间,S表示 Smoothed 。因为进行的是加权平均,因此得出的结果更加平滑)。每当第一次测量到RTT样本时,RTTs值就取为所测量到的RT样本值。但以后每测量到一个新的RT样本,就按下式重新计算一次RTTs:
新的RTTs=(1 - α)×(旧的RTTs)+α×(新的RTT样本)
        在上式中,0≤α<1。若α很接近于零,表示新的RTTs值和旧的RTTs值相比变化不大,而对新的RTT样本影响不大(RTT值更新较慢)。若选择α接近于1,则表示新的RTTs值受新的RTT样本的影响较大(RTT值更新较快)。已成为建议标准的RFC6298推荐的α值为1/8,即0.125。用这种方法得出的加权平均往返时间RTTs就比测量出的RTT值更加平滑。
超时重传时间:RTO=RTTs+4×RTTd
新的RTTd=(1-β)×(旧的RTTd)+β×|RTTs-新的RTTd样本|,这里β推荐值为0.25

        现在还有一个问题:发送出一个报文段,设定的重传时间到了,还没有收到确认。于是重传报文段。经过了一段时间后,收到了确认报文段。现在的问题是:如何判定此确认报文段是对先发送的报文段的确认,还是对后来重传的报文段的确认?由于重传的报文段和原来的报文段完全一样,因此源主机在收到确认后,就无法做出正确的判断,而正确的判断对确定加权平均RTTs的值关系很大。
若收到的确认是对重传报文段的确认,但却被源主机当成是对原来的报文段的确认,则这样计算出的RTT和超时重传时间RTO就会偏大。若后面再发送的报文段又是经过重传后才收到确认报文段,则按此方法得出的超时重传时间RTO就越来越长。
同样,若收到的确认是对原来的报文段的确认,但被当成是对重传报文段的确认,则由此计算出的RTTs和RTO都会偏小。这就必然导致报文段过多地重传。这样就有可能使RTO越来越短。
        根据以上所述,Karn提出了一个算法:在计算加权平均RTTS时,只要报文段重传了,就不采用其往返时间样本。这样得出的加权平均RTTS和RTO就较准确。
        但是,这又引起新的问题。设想出现这样的情况:报文段的时延突然增大了很多。因此在原来得出的重传时间内,不会收到确认报文段。于是就重传报文段。但根据Kam算法,不考虑重传的报文段的往返时间样本。这样,超时重传时间就无法更新。
        因此要对Karn算法进行修正。方法是:报文段每重传一次,就把超时重传时间RTO增大一些。典型的做法是取新的重传时间为旧的重传时间的2倍。当不再发生报文段的重传时,才根据上面给出RTO=RTTs+4×RTTd计算超时重传时间。实践证明,这种策略较为合理。
        总之,Kam算法能够使运输层区分开有效的和无效的往返时间样本,从而改进了往返时间的估测,使计算结果更加合理。

选择确认
        接收方收到了和前面的字节流不连续的两个字节块。如果这些字节的序号都在接收窗口之内,那么接收方就先收下这些数据,但要把这些信息准确地告诉发送方,使发送方不要再重复发送这些已收到的数据。

        TCP的首部没有哪个字段能够提供记录字节块的边界信息。RFC2018规定,如果要使用选择确认SACK,那么在建立TCP连接时,就要在TCP首部的选项中加上“允许SACK”的选项,而双方必须都事先商定好。如果使用选择确认,那么原来首部中的“确认号字段”的用法仍然不变。只是以后在TCP报文段的首部中都增加了SACK选项,以便报告收到的不连续的字节块的边界。由于首部选项的长度最多只有40字节,而指明一个边界就要用掉4字节(因为序号有32位,需要使用4个字节表示),因此在选项中最多只能指明4个字节块的边界信息。这是因为4个字节块共有8个边界,因而需要用32个字节来描述。另外还需要两个字节。一个字节用来指明是SACK选项,另一个字节是指明这个选项要占用多少字节。如果要报告五个字节块的边界信息,那么至少需要42个字节。这就超过了选项长度的40字节的上限。互联网建议标准RFC2018还对报告这些边界信息的格式都做出了非常明确的规定,这里不再赘述。

流量控制

        所谓流量控制,就是让发送方的发送速率不要太快,要让接收方来的及接收。

滑动窗口实现流量控制:

TCP传输效率:

        例如,交互式用户使用一条 TELNET 连接(运输层为TCP协议)。假设用户只发1个字符,加上20字节的首部后,得到21字节长的TCP报文段。再加上20字节的卫首部,形成41字节长的IP数据报。在接收方TCP立即发出确认,构成的数据报是40字节长(假定没有数据发送)。若用户要求远地主机回送这一字符,则又要发回41字节长的I数据报和40字节长的确认IP数据报。这样,用户仅发1个字符时,线路上就需传送总长度为162字节共4个报文段。当线路带宽并不富裕时,这种传送方法的效率的确不高。因此应适当推迟发回确认报文,并尽量使用捎带确认的方法。
        在TCP的实现中广泛使用Nage算法。算法如下:若发送应用进程把要发送的数据逐个字节地送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。当发送方收到对第一个数据字符的确认后,再把发送缓存中的所有数据组装成报文段发送出去,同时继续对随后到达的数据进行缓存。只有在收到对前一个报文段的确认后才继续发送下一个报文段。当数据到达较快而网络速率较慢时,用这样的方法可明显地减少所用的网络带宽。 Nagle 算法还规定,当到达的数据已达到发送窗口大小的半或已达到报文段的最大长度时,就立即发送一个报文段。这样做,就可以有效地提高网络的吞吐量。
        另一个问题叫做糊涂窗口综合征[RFC 813],有时也会使TCP的性能变坏。设想一种情况:TCP接收方的缓存已满,而交互式的应用进程一次只从接收缓存中读取1个字节,然后向发送方发送确认,并把窗口设置为1个字节。接着,发送方又发来1个字节的数据。接收方发回确认,仍然将窗口设置为1个字节。这样进行下去,使网络的效率很低。
        要解决这个问题,可以让接收方等待一段时间,使得或者接收缓存已有足够空间容纳个最长的报文段,或者等到接收缓存已有一半空闲的空间。只要出现这两种情况之一,接收方就发出确认报文,并向发送方通知当前的窗口大小。此外,发送方也不要发送太小的报文段,而是把数据积累成足够大的报文段,或达到接收方缓存的空间的一半大小。
上述两种方法可配合使用。使得在发送方不发送很小的报文段的同时,接收方也不要在缓存刚刚有了一点小的空间就急忙把这个很小的窗口大小信息通知给发送方

拥塞控制

原因:对资源的需求>可用资源
四种拥塞控制的算法:慢开始、拥塞避免、快重传、快恢复
慢开始:当主机开始发送数据的时候,先探测一下,即由小到大逐渐增大发送窗口(即由小到大增大拥塞窗口的值)。初始cwnd=1,发送方只要顺利收到一个对新报文段的确认,其拥塞窗口cwnd就立即加一。
避免拥塞:达到ssthresh值时,拥塞窗口开始从指数增长切换为线性增长。
快重传:发送方只要一收到3个重复确认报文,证明出现报文丢失(但不是因为网络拥塞造成的报文丢失),立即进行重传,这样就不会出项超时,发送方也就不会误认为网络出现拥塞。
快恢复:发送方一连收到3个重复确认报文,知道只是丢失了个别报文,将门限值调整为ssthresh=cwnd/8

        首先,慢开始cwnd=1,然后指数增加cwnd,到ssthresh设定的阈值,启动拥塞避免算法,开始线性增长,当cwnd=24时,网络法生拥塞,cwnd降为1启动慢开始算法,同时调整ssthresh=24/2=12,然后指数增加cwnd,到ssthresh设定的阈值12,启动拥塞避免算法,开始线性增长,当cwnd=16时,发送方一连收到三个确认报文,执行快重传和快恢复算法,调整ssthresh=cwnd/2=8,执行拥塞避免算法。

主动队列管理AQM

所谓“主动”队列管理就是不要等路由器队列长度已经达到最大数值时才不得不丢弃后面到达的分组,这样就太被动了,(随即早期丢弃)RED算法可以实现主动队列管理,具体实现:需要路由器维持两个参数,即队列最小门限和最大门限。当一个分组到达时,RED就按照规定算法计算当前平均队列长度。
(1)若平均队列长度小于最小门限,则把新到达的分组放入队列进行排队。
(2)若平均队列长度超过最大门限,则把新到达的分组丢弃。
(3)若平均队列长度在最小门限和最大门限之间,则按照某一丢弃概率p把新到达的分组丢弃(这就体现了丢弃分组的随机性)
这样一来,使网络中随机的一些TCP连接先启动慢开始,就可以避免网络中一股脑的超时,然后又一股脑的慢开始,造成网络周期性的出现拥塞。当都进行慢开始时,路由器又处于空闲状态浪费路由器处理资源,当速度都提升上来,网络肯定又会出现拥塞。执行RED算法,可以让网络流量得到均衡。

运输连接管理

        TCP是面向连接的协议。运输连接是用来传送TCP报文的。TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。因此,运输连接就有三个阶段,即:连接建立、数据传送和连接释放。运输连接的管理就是使运输连接的建立和释放都能正常地进行。
在TCP连接建立过程中要解决以下三个问题
(1)要使每一方能够确知对方的存在。
(2)要允许双方协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)
(3)能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。
        TCP连接的建立采用客户服务器方式。主动发起连接建立的应用进程叫做客户( client ),而被动等待连接建立的应用进程叫做服务器( server )

TCP连接建立与释放

https://blog.csdn.net/qq_42196196/article/details/81042376

猜你喜欢

转载自blog.csdn.net/qq_42196196/article/details/83865752
今日推荐