• 第3章 TCP协议详解


    第3章 TCP协议详解


    3.1 TCP服务的特点

    传输协议主要有两个:TCP协议和UDP协议,TCP协议相对于UDP协议的特点是

    • 面向连接
      使用TCP协议通信的双方必须先建立连接,完成数据交换后,通信双方都必须断开连接以释放系统资源.

    • 字节流

      发送端执行的写操作次数和接收端执行的读操作次数之间没有任何数量关系.

      相比UDP则是发送端每执行一次写操作,UDP模块就将其封装成一个UDP数据报并发送之.为避免丢包,接收端必须及时针对每一个UDP数据报执行读操作.

    • 可靠传输

      1) TCP协议采用发送应答机制,即发送端发送的TCP报文都得到了接收方的应答才算传输成功;

      2) TCP协议采用超时重传机制,即发送端在发送出一个TCP报文段后启动定时器,若在定时时间内未收到应答,将会重发该报文.

    TCP报文最终是以IP数据报发送的,而IP数据报的特点是无状态,无连接,不可靠的,即接收端可能收到乱序,重复的TCP报文段,所以TCP协议还会对接收到的TCP报文段进行重排与整理,再交付给应用层.


    3.2 TCP头结构

    TCP头部信息出现每一个TCP报文段中.

    0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |          Source Port          |       Destination Port        |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                        Sequence Number                        |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                    Acknowledgment Number                      |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |  Data |           |U|A|P|R|S|F|                               |
    | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
    |       |           |G|K|H|T|N|N|                               |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |           Checksum            |         Urgent Pointer        |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                    Options                    |    Padding    |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                             data                              |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    
    • 16位源/目的端口号(Source Port&Destination Port) : 告知主机该报文来自哪里以及传给哪个上层协议或应用程序.查看知名服务可使用"cat /etc/services"

    • 32位序列号(Sequence Number) : 一次TCP通信过程中一个传输方向上的字节流的每个字节的编号.假设主机A和B进行TCP通信,A发送给B的第一个TCP报文段中,序列值被系统初始化为某个随机值ISN(Initial Sequence Number,初始序列号),那么在该传输方向上,后续的TCP报文段中序号值将被系统设置成ISN加上该报文段所携带数据的第一个字节在整个字节流中的偏移.

    • 32位确认号(Acknowledgment Number) : 用作对另一方发送来的TCP报文段的响应.其值是收到的TCP报文段的序号加1.

    • 4位头部长度(Data Offset) : 即该TCP头部有多少个32bit字.可见头部最大长度为60字节,包括Options部分.

    • 6位标志位包含如下几项,可以为空

      URG: 表示紧急指针是否有效.

      ACK: 表示确认号是否有效,将拥有此标志的报文段称为确认报文段.

      PSH: 提示接收端应用程序应该立即从TCP接收缓冲区中读走数据.

      RST: 表示要求对方重新连接,将拥有此标志的报文段称为复位报文段.

      SYN: 表示请求一个连接,将拥有此标志的报文段称为同步报文段.

      FIN: 表示通知对方本端要关闭连接了,将拥有此标志的报文段称为结束报文段.

    • 16位窗口大小(Window) : TCP流量控制的一个手段.这里的窗口指的是接受通告窗口(Receiver Window,RWND).它告诉对方本端还能容纳多少字节的数据,以此对方就可以控制发送数据的速度.

    • 16位检码和(TCP checksum) :由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏.检验内容包括TCP头部和数据部分.这是TCP可靠传输的一个重要保障.

    • 16位紧急指针(Urgent Pointer):其值为正的偏移量,它是发送端向接收端发送紧急数据的方法.

    • 选项部分(Options) : 是可变长的可选信息.这部分最多可包含40字节. 在这之前的全为固定部分,占用20字节的大小.

    一.使用tcpdump观察TCP头部信息

    pi@happyPi:~ $ telnet 127.0.0.1
    IP 127.0.0.1.39681 > 127.0.0.1.23: Flags [S], seq 1470116583, win 43690, options [mss 65495,sackOK,TS val 2490119 ecr 0,nop,wscale 7], length 0
    0x0000:  4510 003c cde0 4000 4006 6ec9 7f00 0001
    0x0010:  7f00 0001 9b01 0017 57a0 32e7 0000 0000
    0x0020:  a002 aaaa fe30 0000 0204 ffd7 0402 080a
    0x0030:  0025 ff07 0000 0000 0103 0307
    
    1. 127.0.0.1.39681 > 127.0.0.1.23 表示从127.0.0.1的39681端口 发送至 127.0.0.1的23端口.

    2. Flags [S] 表示该TCP报文段包含SYN标志,因此是一个同步报文段.

    3. seq 1470116583 ,由于此报文是这个传输方向上第一个TCP报文段,所以这个序列号就是一个ISN.

    4. 由于是整个通信过程中的第一个TCP报文段,所以它没有针对对方发送来的TCP报文段的确认值.

    5. win 43690 , 表示接受通告窗口的大小,反映的是实际的接受通告窗口大小.

    6. mss(Max Segment Size,MSS) 65495 ,它是通信双方协调最大报文段长度,一般会设置为(MTU-40)字节,40=20(IP头部)+20(TCP头部),从而避免发生IP分片,对于以太网来说,MSS值是1460(1500-40)字节.

    7. sackOK : sack(Selective Acknowledgment,选择性确认)使得TCP模块只重新发送丢失的TCP报文段,不用发送所有未被确认的TCP报文段.

    8. wscale : wscale(window scale,窗口扩大因子)为了解决接收通告窗口太小的问题,因为接收窗口大小是用16位表示的,所以最大为65535(216-1)字节,但实际上TCP模块允许的接收通告窗口大小远不止这个数.若wscale为M,则表示实际接收通告窗口大小为N * 2M,N为win的大小.

    二.对于TCP头部的解析:

    0x0000:  4510 003c cde0 4000 4006 6ec9 7f00 0001
    0x0010:  7f00 0001 9b01 0017 57a0 32e7 0000 0000
    0x0020:  a002 aaaa fe30 0000 0204 ffd7 0402 080a
    0x0030:  0025 ff07 0000 0000 0103 0307
    

    由于TCP报文被IP协议封装过(IP头部大小为20字节),所以得从21字节开始看TCP的头部.

    将IP头部的用"...."替换.

    0x0000:  .... .... .... .... .... .... .... ....
    0x0010:  .... .... 9b01 0017 57a0 32e7 0000 0000
    0x0020:  a002 aaaa fe30 0000 0204 ffd7 0402 080a
    0x0030:  0025 ff07 0000 0000 0103 0307
    
    • 9b01 : 对应源端口号39681.

    • 0017 : 对应目的端口号23.

    • 57a0 32e7 : ‭序号1470116583‬.

    • 0000 0000 : 确认号 0,tcpdump中未显示.

    • a : 10个32bit,即10*(32/8) = 40字节.

    • 002 : 将其去掉六位保留位,得到000002,标识码.

    • aaaa : 窗口大小‭43690‬.

    可见TCP报文段头部的二进制和tcpdumTp输出的CP报文段描述信息完全对应.

    在后面的分析,将仅显示序号,确认号,窗口大小以及标志位等与讨论主题有关的字段.


    3.3 TCP连接的建立和关闭

    一. TCP连接的建立与三次握手

    1. 源机器对目标机器发起请求(seq:535734930 , Flags[S] , length 0)

    2. 目标机器收到请求,同意与源机器连接,并回复给源机器(seq:2159701207 , Flags[S.] , ack:535734931 , length 0)

    3. 对目标机器回复的报文的确认(Flags[.] , ack:2159701208 , length 0).

    这里值得注意的是本来seq(序列号)是用来标识TCP数据流中的每一个字节的,但是同步报文段比较特殊,即使它并没有携带任何应用程序数据,它也要占用一个序列值.

    ack为确认号(Acknowledgment Number) , 其值为接收到的同步报文段的序列号加1.

    以上三个步骤被称为TCP的三次握手.

    二.TCP连接的关闭

    1. 源机器对已建立TCP连接的目标机器告之要关闭本连接(seq:535734931,ack:2159701208,Flags[F.],length 0)

    2. 目标机器收到通告,并发送确认信息.(ack:535734932 , length 0)

    3. 目标机器发送自己的结束报文段告之要关闭本连接(seq:2159701208,ack:535734932,Flags:[F.],length 0)

    4. 源机器发收到通告,并发送确认信息(ack:2159701209 , length 0).

    一般而言,TCP连接是由客户端发起的,并通过三次握手建立(特殊情况是同时打开)的.

    而TCP的关闭过程有这么几种可能:

    1. 可能是客户端执行主动关闭,比如前面举的例子.

    2. 可能是服务器执行主动关闭,比如服务器程序被中断而强制关闭连接.

    3. 可能是同时关闭.

    三.TCP连接的半关闭状态

    由于TCP连接是全双工的,所以它允许两个方向(发送和接收)的数据传输被独立关闭.

    因而通信的一端可以发送结束报文段给对方,告之本端已完成数据的发送,但允许继续接收来自对方的数据,直到对方也发送结束报文段以关闭连接.

    TCP的这种状态称之为半关闭状态(half close).

    四.连接超时

    对于提供可靠连接的TCP来说,在连接超时的情况下必然是先进行重连,若多次重连仍然无效,则通知应用程序连接超时.

    由于HTTP(测试中监听了80端口)是基于TCP协议的,所以对于以下的测试可以反映出TCP的重连表现:

    pi@happyPi:~ $ sudo tcpdump -n -i eth0 port 80 &
    pi@happyPi:~ $ wget www.google.com
    11:30:13.695658 IP 192.168.1.108.37366 > 59.24.3.173.80: Flags [S], seq 1964502452, win 29200, options [mss 1460,sackOK,TS val 13783 ecr 0,nop,wscale 7], length 0
    11:30:14.692904 IP 192.168.1.108.37366 > 59.24.3.173.80: Flags [S], seq 1964502452, win 29200, options [mss 1460,sackOK,TS val 13883 ecr 0,nop,wscale 7], length 0
    11:30:16.692946 IP 192.168.1.108.37366 > 59.24.3.173.80: Flags [S], seq 1964502452, win 29200, options [mss 1460,sackOK,TS val 14083 ecr 0,nop,wscale 7], length 0
    11:30:20.702931 IP 192.168.1.108.37366 > 59.24.3.173.80: Flags [S], seq 1964502452, win 29200, options [mss 1460,sackOK,TS val 14484 ecr 0,nop,wscale 7], length 0
    11:30:28.722938 IP 192.168.1.108.37366 > 59.24.3.173.80: Flags [S], seq 1964502452, win 29200, options [mss 1460,sackOK,TS val 15286 ecr 0,nop,wscale 7], length 0
    11:30:44.742930 IP 192.168.1.108.37366 > 59.24.3.173.80: Flags [S], seq 1964502452, win 29200, options [mss 1460,sackOK,TS val 16888 ecr 0,nop,wscale 7], length 0
    11:31:16.822969 IP 192.168.1.108.37366 > 59.24.3.173.80: Flags [S], seq 1964502452, win 29200, options [mss 1460,sackOK,TS val 20096 ecr 0,nop,wscale 7], length 0
    failed: Connection timed out.
    

    可以看到重连的时间间隔为[1,2,4,8,16,32]s,而且重连了6次数.

    关于次数,是由"/proc/sys/net/ipv4/tcp_syn_retries"内核变量来决定的.

    pi@happyPi:~ $ cat /proc/sys/net/ipv4/tcp_syn_retries 
    6
    

    3.4 TCP状态连接

    一.客户端的状态

    • 建立连接
    右边是状态名称且状态过程是从左到右 SYN_SENT ESTABLISHED
    原因 使用系统调用connect发送一个同步报文段 收到服务器的确认报文段
    进一步的操作 回复给服务端确认报文段
    • 关闭连接
    右边是状态名称,状态过程是从左到右 FIN_WAIT_1 FIN_WAIT_2 TIME_WAIT
    原因 向服务器发送结束报文段 收到服务器的确认报文段 收到服务器结束报文段
    进一步的操作 回复给服务端确认接收报文段
    备注 FIN_WAIT_1可直接至TIME_WAIT

    二.服务端的状态

    • 建立连接
    右边是状态名称,状态过程是从左到右 LISTEN SYN_RCVD ESTABLISHED
    原因 使用系统调用listen监听请求连接 监听到某个请求连接 收到客户端确认报文段
    进一步的操作 回复给客户端确认报文段
    • 关闭连接
    右边是状态名称,状态过程是从左到右 CLOSE_WAIT LAST_ACK CLOSED
    原因 收到客户端的结束报文段 发送给客户端结束报文段 收到客户端的确认报文段
    进一步的操作 回复给客户端确认报文段

    由以上的过程可以得到下面几个结论:

    1. 对于TCP的连接建立,一般来讲是客户端早于服务端,因为服务端的通信建立完成还得收到客户端的确认报文段,而此时客户端已经建立完成.

    2. 处于FIN_WAIT_2状态的客户端需要等待服务器发送结束报文段,才能转移至TIME_WAIT,否则将一直停留在这个状态.

    3. 在备注里提过的,FIN_WAIT_1状态可以直接进入TIME_WAIT(不经过FIN_WAIT_2),前提是处于FIN_WAIT_1状态的服务器直接收到带确认信息的结束报文段(而不是先接收确认报文段,再接收结束报文段).

    长时间处于FIN_WAIT_2状态的连接称之为孤儿连接,Linux为防止孤儿连接长时间留在内核中,定义了以下两个变量,分别指定内核能接管的孤儿连接数目与其在内核中生存的时间.

    pi@happyPi:~ $ cat /proc/sys/net/ipv4/tcp_max_orphans 
    4096
    pi@happyPi:~ $ cat /proc/sys/net/ipv4/tcp_fin_timeout 
    60
    

    三.TIME_WAIT状态

    在上面客户端关闭的状态中有一个是TIME_WAIT,即在客户端收到服务器的结束报文段之后,并没有直接进入CLOSED状态.

    TIME_WAIT有两个原因:

    • 可靠的终止TCP连接,因为避免回复给服务器的确认报文段发送失败.

    • 保证让迟来的TCP报文段有足够的时间被识别并丢弃.万一关闭此端口后被其他程序使用并收到了原来的数据报.

    有时我们希望避免TIME_WAIT状态,因为当程序退出后,我们希望能够立即重启它.但由于处在TIME_WAIT状态的连接还占用着端口,程序将无法启动(直到MSL(Maximum Segment Life,报文段最大生存时间)超时时间结束,标准文档建议的MSL为2min).

    对于客户端程序来说,通常不用担心上面描述的重启问题,因为它们一般使用系统自动分配的临时端口号建立连接,由于随机性,一般会与上次(还处于TIME_WAIT状态的端口号)使用的不同.但如果总是异常终止则说明使用的是一个知名服务端口号.

    下图是在Windows上TCP连接的状态:

    活动连接
    
      协议  本地地址          外部地址        状态
    [cloudmusic.exe]
      TCP    192.168.1.106:13355    119.44.11.138:http     ESTABLISHED
     [cloudmusic.exe]
      TCP    192.168.1.106:13359    119.44.11.138:http     ESTABLISHED
     [cloudmusic.exe]
      TCP    192.168.1.106:13360    119.44.11.138:http     ESTABLISHED
     [cloudmusic.exe]
      TCP    192.168.1.106:13362    119.44.18.47:http      LAST_ACK
     [cloudmusic.exe]
      TCP    192.168.1.106:13366    119.44.11.138:http     ESTABLISHED
     [cloudmusic.exe]
      TCP    192.168.1.106:13392    tsa01s08-in-f14:https  LAST_ACK
     [firefox.exe]
      TCP    192.168.1.106:13394    ti-in-f138:http        SYN_SENT
     [firefox.exe]
      TCP    192.168.1.106:13395    ti-in-f101:http        SYN_SENT
     [firefox.exe]
      TCP    192.168.1.106:13396    59.111.160.195:http    LAST_ACK
     [cloudmusic.exe]
      TCP    192.168.1.106:13397    119.44.18.47:http      ESTABLISHED
     [cloudmusic.exe]
      TCP    192.168.1.106:13398    ti-in-f138:http        SYN_SENT
     [firefox.exe]
      TCP    192.168.1.106:13399    ti-in-f101:http        SYN_SENT
     [firefox.exe]
    

    可以看到这些状态是可以在系统中明文标注出来的.进以分析出当前某个程序的连接状态.


    3.5 复位报文段

    产生复位报文段的三种情况:

    1. 访问不存在的端口.

    2. 目标端口仍处于TIME_WAIT状态.

    3. 处理半打开连接.半打开即通信双方关闭或者异常终止了连接,而未通知对方,并继续向对方发送数据报.

    这在第1种情况下抓取到的TCP报文段:

    pi@happyPi:~ $ sudo tcpdump -nt -i eth0 port 54321 &
    pi@happyPi:~ $ telnet  192.168.1.100 54321
    Trying 192.168.1.100...
    IP 192.168.1.108.48326 > 192.168.1.100.54321: Flags [S], seq 1285841519, win 29200, options [mss 1460,sackOK,TS val 4294956710 ecr 0,nop,wscale 7], length 0
    IP 192.168.1.100.54321 > 192.168.1.108.48326: Flags [R.], seq 0, ack 1285841520, win 0, length 0
    

    可见收到了带Flags[R.]的报文段.


    3.6 TCP数据流

    本节讨论通过TCP连接交换的应用程序数据,TCP报文段所携带的应用程序数据按照长度分为两种:

    • 交互数据

    • 成块数据

    前者对实时性要求高如telnet与ssh等,后者对传输效率要求高如ftp等.

    一. TCP交互数据流

    这种数据流的传输方式有一个特点,服务器每次发送的确认报文段都包含它需要发送的应用程序数据.服务器的这种处理方式称为延迟确认,即它不马上确认上次收到的数据,而是在一段延迟时间后查看本端是否还有数据需要发送,若有,则和确认信息一起发出,这样做的理由是为了减少发送TCP报文段的数量.

    在局域网中交互数据流可能经受很大的延迟,并且,携带交互数据的微小TCP报文段数量一般很多(客户端上一个按键就会导致一个TCP报文段),这些因素都可能导致拥塞发生,解决这个问题的一个简单有效的方法是使用Nagle算法,它会要求一个TCP连接的通信双方在任意时刻都最多只能发送一个未被确认的TCP报文段.具体的表现在于,发送方在等待确认的同时,收集本端需要发送的微量数据,并在确认信息到来时以一个TCP报文段将他们全部发出,如此一来就极大的减少了网络上微小TCP报文段的数量.表面上看来就是"确认到达的越快,数据就发送的越快".

    二. TCP成块数据流

    当传输大量大块数据的时候,发送方会连续发送多个TCP报文段(由于文件太大),但是接收方可以一次确认这些所有这些报文段.

    而且发送方会根据接收方的报文段中接收通告窗口(Window)的大小了解到接收方的接收缓冲区还有多少空闲空间,并且可能会发送一个带PSH标志的报文段以通知应用程序尽快读取数据.

    三.带外(Out Of Band,OOB)数据

    带外数据用于通告对方本端发生的重要事件.因此,带外数据比普通数据有更高的优先级,它应该是被立即发送,而无论发送缓冲区是否有排队等待发送的普通数据.并且它可以使用一条独立的传输层连接,也可以映射到传输普通数据的连接中.

    UDP/TCP没有真正的带外数据,不过TCP利用其头部中的紧急指针标志和紧急指针两个字段,给应用程序提供了一种紧急方式.

    TCP接收端只有在接收到紧急指针标志时候才会检查紧急指针,然后根据紧急指针所指的位置确定带外数据的位置,并将它读入一个特殊的缓存中(这个缓存只有1字节,称为带外缓存).若上层应用没有及时取走带外缓存中的数据,则后续的带外数据将覆盖它.当然,通过设置相关参数,带外数据也可以像普通数据一样被TCP模块存放在TCP接收缓存区.


    3.9 TCP超时重传

    若在建立正常连接后突然网络状况异常甚至与服务器直接断开,TCP必须能够重传超时间内未收到确认的TCP报文段,为此,TCP模块为每个TCP报文段都维护一个重传定时器,该定时器在TCP报文段第一次被发送时启动.如果超时时间内未收到接收方的应答,TCP模块将重传TCP报文段并重置定时器.至于下次重传的超时时间如何选择,以及最多执行多少重传,这就是TCP的重传策略.

    在Linux上有两个重要内核参数与TCP重传相关,他们分别是在底层IP接管之前TCP最少执行的重传次数和连接放弃前TCP最多可以执行的重传次数.

    pi@happyPi:~ $ cat /proc/sys/net/ipv4/tcp_retries1
    3 
    pi@happyPi:~ $ cat /proc/sys/net/ipv4/tcp_retries2
    15
    

    在TCP重传机制下多次尝试失败的情况下,将会交给底层的IP和ARP接管,直到所使用的应用程序放弃连接为止.


    3.10 拥塞控制

    由于TCP模块还有一个重要任务,就是提高网络利用率,降低丢包率,并保证网络资源对每条数据流的公平性,这就是所谓的拥塞机制.

    TCP的拥塞机制有四个部分:

    • 慢启动(slow start).

    • 拥塞避免(congestion avoidance).

    • 快速重传(fast retransmit).

    • 快速恢复(fast recovery).

    拥塞算法在Linux下有多种实现,比如reno/vegas/cubic算法,在Linux机器上,"/proc/sys/net/ipv4/tcp_congestion_control"中指示了机器当前所使用的拥塞机制控制算法.

    pi@happyPi:~ $ cat /proc/sys/net/ipv4/tcp_congestion_control 
    cubic
    

    下面介绍在发送数据时起到影响数据发送量的几个术语:

    SWND(Send Window,发送窗口) SMSS(Sender Maximum Segment Size,发送者最大段大小) RWND(Receiver Window,接收窗口) CWND(Congestion Window,拥塞窗口)
    发送端向网络一次连续写入的数据量 发送者最大段大小,一般等于MSS 接收方可通过其控制发送端的SWND 最终用来控制发送端的SWND,实际值是RWND和CWND的较小者

    发送端需要合理的选择SWND的大小,如果SWND太小,会引起明显的网络延迟;反之,若SWND太大,则容易导致网络拥塞.TCP的拥塞机制最重要的任务就是调整CWND的大小,因为它才是最终的SWND.

    在TCP连接建立好之后,CWND会被设置为初始值IW(Initial Window),其大小为SMSS的整数倍.
    接着为避免拥塞:

    1. CWND += MIN(N,SMSS).(N为此次确认中包含的之前未被确认的字节数)    (3.0)
      当CWND大于ssthresh(slow start threshold size,慢启动门限),进入第2步.

    2. CWND += SMSS * SMSS/CWND.    (3.1)
      使得CWND按照线性方式增长,从而减缓其扩大.

    若发生了拥塞,则可能是下面两种情况引起的:

    • 传输超时(TCP重传定时器溢出).

    • 接收到重复的确认报文段.

    若是前者的情况,则立即重传并通过如下公式的调整,SWND将小于SMSS,也小于ssthresh,同时再次进入慢启动阶段.

    ssthresh = max(FlightSize / 2,2 * SMSS),CWND <= SMSS    (3.2)

    若是后者的情况,按照收到的确认报文段数量不同做出相应的反映:

    1. 当收到第3个重复的确认报文段时,就认为网络真的发生拥塞了.按照公式(3.2)计算ssthresh,然后立即重传丢失的报文段,接着设置CWND = ssthresh+3*SMSS.

    2. 每次收到1个重复的确认时,设置CWND += SMSS.

    3. 当收到新数据的确认时,按照公式(3.2)计算ssthresh,接着CWND=ssthresh.

    快速重传和快速恢复完成之后,拥塞控制将恢复到拥塞避免阶段,由第三步可得知.

    综合以上的可见关键在于根据当前网络的状态调整CWND的大小以提高传输效率.


    关于第3章的总结

    这一章从四个部分学习了TCP协议:

    1. TCP头部信息.主要是通信的端口指定,TCP连接的管理,控制通信双方的数据流.

    2. TCP状态转移过程.主要是通信双方在连接到关闭整个过程的状态变化.

    3. TCP数据流.主要是交互数据流和成块数据流.

    4. TCP数据流的控制.主要是超时重传和拥塞控制.

    这一章知识点比较多,对TCP的整体有了一个整体的了解.它比IP协议具有更强的可操作性.


    From

    Linux 高性能服务器编程 游双著 机械工业出版社

    MarkdownPad2

    2017/1/21 0:00:09

  • 相关阅读:
    python学习笔记(unittest)
    python学习笔记(session)
    python学习笔记(requests)
    jmeter的学习(配置环境)
    Codeforces 576D. Flights for Regular Customers 题解
    Codeforces 1316F. Battalion Strength 题解
    2020年第十一届蓝桥杯省赛J-网络分析(带权并查集)
    第十一届蓝桥杯b组省赛 C.合并检测(内附详细的样例)
    蓝桥杯2020.7月真题走方格(到达终点的不同方案数)(记忆化搜索+DP)
    Codeforces Global Round 11 A. Avoiding Zero(思维构造)
  • 原文地址:https://www.cnblogs.com/leihui/p/6394423.html
Copyright © 2020-2023  润新知