传输层UDP/TCP协议

Posted 两片空白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了传输层UDP/TCP协议相关的知识,希望对你有一定的参考价值。

目录

前言

 一.五元组

        1.1 概念

         1.2 端口号范围划分

        1.3 关于网络的命令

二.UDP协议

        2.1 格式

        2.2 特点

        2.3 UDP的缓冲区

         2.4 UDP使用注意事项

        2.5 基于UDP协议的应用层协议

        2.6 UDP在内核中的实现

三.TCP协议

        3.1 tcp协议特点

        3.2 确认应答机制 

        3.3 tcp协议格式

        3.4 超时重传机制

                3.4.1概念 

                3.4.2超时重传时间

         3.5 连接管理机制

                3.5.1三次握手和四次挥手

                3.5.2 四次挥手TIME_WAIT状态

                3.5.3 四次挥手CLOSE_WAIT状态

        3.6 滑动窗口

        3.7 流量控制

        3.8 拥塞控制

        3.9 延时应答

        3.10 捎带应答


前言

        负责数据能够从发送端传输到接收端。

 一.五元组

        1.1 概念

        端口号:标识另一台主机上的一个进程。

        端口号如何找到进程?内核实现通过哈希算法,端口号对应进程PID。

        在TCP/IP协议中,用"源IP","目的IP","源端口号","目的端口号","协议号",这五元组来标识一个通信。

        源IP:发送数据的主机IP

        目的IP:最终接收数据主机IP

        源端口号:发送数据主机中发送数据的进程

         目的端口号:最终接收数据主机中要接收数据的进程。

        注意:源IP,目的IP,源端口号和目的端口号在传输过程中是不变的,会变化的是MAC地址(标识网卡)。

         1.2 端口号范围划分

  • 0~1023:知名端口号。这些端口号是固定的,已经和一些进程强绑定了。我们不能使用。
  • 1024~65535:操作系统动态分配的端口号,可以由用户或者系统从这个范围里分配。

一些知名端口号:

  • ssh服务器,使用22端口号
  • ftp服务器,使用21端口号
  • telnet服务器,使用23端口号
  • http服务器,使用80端口号
  • https服务器,使用443端口号

使用命令 cat /etc/services 可以查看指明端口号。

注意:一个进程可以绑定多个端口号,一个端口号只能绑定一个进程。

        1.3 关于网络的命令

  • netstat

作用:查看网络状态。

选项:

  1. n:能显示数字的全部转化成数字
  2. l:列出有在Listen(监听)的服务状态。
  3. p:显示奖励相关连接的程序名
  4. t(tcp):仅显示tcp相关选项
  5. u(udp):仅显示udp相关选项
  6. a(all):显示所有选项
  •  pidof

作用:查看服务器进程id

语法:pidof [进程名(可执行程序名)]

  •  ifconfig

作用:用于显示或者设置网络设备

  •  telnet

作用:连接服务

二.UDP协议

        2.1 格式

  •  16位源端口号:发送数据主机中发送数据的进程
  • 16位目的端口号:最终接收数据主机中要接收数据的进程。
  • 16位UDP长度:整个数据报的最大长度(UDP报头+数据)。
  • 15位检验和:检验数据是否出错,出错直接丢弃。

 网络每一层主要都要解决两个问题:

1.如何做到数据和报头的有效分离?

        UDP报头是定长的8字节,可以将报头分离。报头的16位UDP长度减去8字节,就是数据长度。

2.如何做到向上交付给什么谁?

        传输层向上交付,交付给应用层,实际是交付给应用层的某个进程,目的端口号确认交付给哪个进程。

        2.2 特点

  • 无连接:知道对方的IP和端口号就可以直接传输,不需要建立连接。
  • 不可靠:没有确认机制,没有重传机制。数据丢了就是丢了,并且也不会向应用层返回任何错误信息。
  • 面向数据报:将数据整个发送,整个接收。应用层给UDP的多长的报文,UDP只会原样发送,既不会拆分也不会合并,只是加一个自己协议的报头。

        2.3 UDP的缓冲区

        UDP没有真正意义上的发送缓冲区,调用sendto直接将数据交给内核,由内核将数据传给网络层。

        UDP有接收缓冲区,但是这个缓冲区不能保证收到的UDP数据报顺序和发送UDP数据报的顺序一致,如果接收缓冲区满了,再到达UDP的数据会被直接丢弃,丢弃之后也不管了。

        顺序接收也是可靠性的一种。

        数据发送是一次性发送多条数据,发送数据的顺序和接收数据的顺序不一定一致,因为可能选择的网络路径不同。

        UDP的socket既能读,也能写,是全双工的。

         2.4 UDP使用注意事项

        UDP包头中UDP最大长度只有16位,说明UDP能够传输的数据最大的长度是64k(包括报头)。

        如果我们需要传输的数据超过64k,就需要在应用层手动进行分包,多次发送,并且在接收端手动拼装。

        2.5 基于UDP协议的应用层协议

  • NFS:网络文件系统
  • TFTP:简单文件传输协议
  • DHCP:动态主机配置协议
  • BOOTP:启动协议(用于无盘设备启动)
  • DNS:域名解析协议

        2.6 UDP在内核中的实现

 如何于数据拼接?只需要用udphdr定义变量,在和数据进行拼接即可。(比如memcopy)

三.TCP协议

        TCP协议全称“传输控制协议”。

        TCP协议在内核中有自己的接收和发送缓冲区。

        3.1 tcp协议特点

  • 有连接:不仅需要知道对方IP地址和端口号,还需要建立连接(connect接口)。
  • 可靠:具有确认机制和重传机制。会对数据进行检测,错误或者丢失,会对数据进行重传。
  • 面向字节流:数据是以字节的形式发出。 

        3.2 确认应答机制 

        发送端发送数据,数据可能会在网络中丢失,发送方怎么知道接收方接收到了数据呢?

        发送方发送数据后,接收方会给发送方响应一个ACK(没有携带数据),表示自己收到了数据。如果发送方没有收到接收方的确认应答,会重发数据。这种机制叫做确认应答机制。

        3.3 tcp协议格式

  •  16位源端口号/目的端口号:表示数据从哪个进程来,到哪个进程去。
  • 32位序号:

        TCP传输数据是按字节流的,按字节为单位发送数据。

        在发送数据时,是一次性发送多条数据,接收端收到数据的顺序不一定和发送端发送数据的顺序一致,因为可能走的网络路径不同,不一致的话,可能导致最终数据错误。

        TCP为了保证数据是有序的,会将发送的每一个字节的数据编号。接收方虽然在接收数据时不一定是有序的,但是在就收到数据后,会按照序号将数据排好序,放在接收缓冲区中。

        序列号保证了,数据的有序性。

  • 32位确认序号

        确认序列号是接收方收到数据后,向发送方确认应答时,在报文的确认序列号中填写的序号。

        确认序列号在原始序列号的基础上加1。有两个作用

  1. 告诉发送方,在此确认序列号之间的数据,都收到了。
  2. 告诉发送方,下一次发送数据时的序列号。

        注意:发送端发送数据,一次性会发送很多,会有很多序列号,但是,接收方应答时,之后应答一个确认序列号。理论上应答需要所有的都应答,由于内核发送数据是有滑动窗口,只需要发一条最新的就好了。

        比如:数据序列号位1,2,3,4发送给接收端,如果3号数据丢失了,接收端会应答一个确认序列号为3。

        第一表示,3号数据之前的数据都受到了。第二表示,之后从3号序列的数据开始发,即3,4是重发的。

 每个字节都进行了编号。

为什么有了序列号,还要有确认序列号。都是用序列号不就可以了?

        因为TCP是全双工的,两台主机之间可能在相互发送数据,如果都使用序列号,序列号就很乱。当一个主机作为发送方时只需要关心序列号,作为接收方时,只需要关心确认序列号。

打消一个疑虑:

        TCP 发送的报文是报头+有效载荷(数据)。这个数据不一定是一字节,要根据流量控制和滑动窗口(后面有介绍)的大小决定。可以是多字节的。

        那是TCP是如何对每一个字节编序的?

        报文下面的数据由多个字节,但是报头的序号中保存的是第一个字节要发送的序号,后面字节的序号,会根据第一个字节序号,和字节个数自己算出来。

        比如:由一个报文,数据又100字节,报头的序号填的是1000,这个1000是100个字节里的第一个字节,TCP可以根据字节数将后面字节的序号算出来。对方响应确认序号会是1100,发送方下一次会从1100序号发送。

  • 4位首部长度

        表示该TCP报头有多少32个bit位(有多少4字节),由于当前位只有4位,所以TCP最大长度的15*4 = 60字节,最小长度位20字节。多余20字节使用选项空间。

为什么在TCP报头中没有正文长度?

        因为TCP是字节流的,按字节传输的,只需要一字节一字节读就好了。

网络每一层主要都要解决两个问题:

1.如何做到数据和报头的有效分离?

        TCP的4位首部长度记录了报头占多少字节,可以区分报头和数据。正文长度并不需要知道,只要一个字节一个字节读就好了。

2.如何做到向上交付给什么谁?

        传输层向上交付,交付给应用层,实际是交付给应用层的某个进程,目的端口号确认交付给哪个进程。

  • 6位标志位

        URG:表示紧急指针是否有效。紧急指针介绍在后面

        ACK:起确认作用

        PSH:提示接受方应用程序立刻从TCP接收缓冲区里把数据拿走。

        RST:对方要求重新建立连接,我们把携带RST标识的称为复位报文段

        比如:当客户端发起连接,三次握手。在第三次客户端向服务器发送ACK时,数据丢失了,服务器没有收到,此时服务器认为没有建立连接。但是客户端发送完ACK后,认为建立起了连接。此时,会向服务器发送数据,服务器收到数据后,因为没有收到连接,会向客户端发送带有RST的响应,客户端收到后,会重新建立连接,三次握手。

        如果客户端连接异常,断开连接了,服务器向客户端发送数据,客户端因为没有连接,向服务器发送RST,服务器收到连接后,由于连接是由客户端建立的,服务器就以为不需要连接了,直接断开连接。

        SYN:请求建立连接,我们把携带SYN标识的称为同步报文段。

        FIN:通知对方,本段要断开连接了。我们称携带FIN标识的为结束报文段。

  •  16位窗口

          有一种情况,当接收方的接收缓冲区满了,当发送方再发送数据,会导致数据丢失,导致发送方需要重发数据。这样很影响效率。TCP为了避免这种情况,采取了流量控制措施。

        流量控制:发送方发送数据时会将自己接送缓冲区中剩余空间的大小填入16位窗口中,告知对方自己还能接收多少数据,如果快满的时候,对方会将数据发慢一点。

        这里要注意,是谁发送,就填谁的接收缓冲区的剩余空间。

        为什么是填发送方的?因为接收方(此时接收方也是发送方)会有应答ACK,此时也会告诉发送方,自己还能接收多少数据。发送方是相对而言的。

  • 16位检验和

        发送端填充,CRC校验,接收端校验不通过,这认为数据有问题。是对整个报文进行校验,数据有问题,会重传数据。

        CRC校验:发送端在每一帧数据后面添加一个校验二进制,这个附加二进制不是随意的,变成一个新数据。发送端和接收端选择某一特定整数整除,由于发送端对其做了处理,新数据整除(其实是"模2除法"从高位开始异或)该数不会出现余数,如果出现余数,说明数据错误。

  • 16位紧急指针:表示哪些数据是紧急数据

        紧急数据优先被执行,6位标志位中URG标识位为1,标识有紧急数据。

        紧急指针:保存的是数据开始位置到紧急数据的偏移量,但是没有标识终止位置,说明紧急数据每次都是一字节。

  • 选项

        有4为首部长度知道,报头最少是20字节,最多为60字节,超过20字节部分为选项部分。

        选项最多有46字节。

TCP是可靠的,解决了两个主要的问题:

1.丢包:用确认应答机制(ACK)和确认序号

2.乱序:32位序号。虽然接收时乱序的,但是会通过序号排序。

在内核源代码中,TCP数据包的结构:

        3.4 超时重传机制

                3.4.1概念 

         当发送端发送数据,如果在一段时间内没有收到应答(ACK),会直接重发数据。

 但是主机A未收到主机B发来的确认应答,也可能是因为ACK丢了。

        主机A一段时间未收到应答会重传数据,主机B收到重复的数据,TCP可以通过序列号识别出重复的数据,并且将重复的数据丢弃,然后发送响应给主机A。

        序列号不仅可以对数据进行排序,还可以起到去重的作用。

                3.4.2超时重传时间

        超时重传时间的长短是随着网络环境的不同,是动态变化的。网络情况差,时间会长一点,网络情况好,会短一点。

        但是,如果超时重传时间设得太长,会影响整体的重传效率。如果时间设得太短,有可能会频繁发送重复的数据报。

        TCP为了保证无论在任何环境下都有比较高性能的通信,会动态计算超时间。

  • Linux中,超时以500ms为一个单位进行控制,每次判定重传时间都是500ms的整数倍。
  • 如果重发一次没有得到响应,会等待2*500ms进行重传。
  • 如果仍没有得到应答,等待4*500ms进行重传,依次类推,以指数形式增长。
  • 但是累计到一定次数的重传次数,TCP会认为对方主机或者网络出现异常,会强制关闭连接。

         3.5 连接管理机制

        首先我们来理解一下连接:

        一台主机可能收到很多的连接,操作系统需要对连接进行管理,先描述后组织。所以连接在内核层会有对应数据结构。所以建立连接是有时间和空间的成本。

        3.5.1三次握手和四次挥手

  • 三次握手

客户端调用connect系统向服务器端建立连接。

        客户端和服务端状态变化:

                服务器必须是从CLOSED->LISTEN(监听)等待客户端连接,调用(listen接口)。

                客户端发起连接(调用connect接口),状态由CLOSED->SYN_SENT(同步发送),发送同步报文SYN。

                服务器接到连接请求状态由LISTEN->SYN_RCVD(同步发送),将该连接放入内核等待队列中,并向客户端发送SYN+ACK压缩报文。

                客户端收到响应,状态由SYN_SENT->ESTABLISHED(连接建立),可以开始发送或者接收数据,并向服务器发送ACK应答报文。

                服务器接到响应,状态由SYN_RCVD->ESTABLISHED(连接建立),可以进行发送和接收数据。至此,连接建立完成。

为什么一定是3次握手才建立连接?

        首先如果是1次握手,客户端发送SYN同步报头后直接建立连接。当客户端发送完连接请求和,直接就认为连接成功,但是并不知道服务器能不能连接。

        其次如果是两次握手,服务器收到连接请求,收到发送响应后,直接就认为连接成功,但是可能响应在网络中阻塞丢失了,客户端并没有建立连接,此时服务器就为此连接开辟了无效的空间,还浪费了时间。

        三次握手解决的两个问题:

        1.三次握手最小成本的验证了全双工。

                TCP协议是全双工的,需要可以收数据和发数据。

        2.让服务器不要出现连接误判的情况,减少服务器开辟连接无效资源的浪费。

                服务器是一对多的,可能会有很多连接。如果两次握手,可能会开辟无效连接资源。

        多余三次握手肯定可以,但是三次握手效率最高。

        注意:三次握手中,如果第三次握手ACK在网络中被堵塞或者丢弃,此时客户端认为连接成功,服务器没有收到连接,没有建立连接。此时客户端发送数据,服务器收到,由于没有建立连接,会向客户端发送带有RST的报文。让客户端重新重新连接。 

  • 四次挥手

状态变化:

        客户端发起断开连接请求,客户端状态由ESTABLISHED->FIN_WAIT1,服务器发送结束报文段(FIN)。

        服务器端收到客户端的关闭请求,服务器端状态由ESTABLISH->CLOSE_WAIT,并返回确认报文段(ACK)。

        客户端收到服务器的响应,客户端状态由FIN_WAIT1->FIN_WAIT2。

        服务器发起断开连接请求,服务器状态由CLOSE_WAIT->LAST_ACK,进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据),当服务器真正调用close关闭连接时,服务器发送FIN,此时服务器会进入LAST_ACK状态,等待最后一个ACK到来。

        客户端收到服务器的断开连接请求,状态由FIN_WAIT2->TIME_WAIT,向服务器端发送ACK。

        服务器收到客户端的响应,状态由LAST_ACK->CLOSED,断开连接,释放连接资源。

        客户端最后状态由TIME_WAIT->CLOSED,等待2*MSL(报文最大生存时间),最后进入CLOSED,断开连接,释放连接资源。

         注意:客户端和服务器端是等四次挥手完成后,状态变为CLOSED后才真正断开连接,才释放连接开辟资源。

        不仅是客户端才能发送断开连接请求,服务器端也可以发送断开连接请求,比如:短连接。只是一般都是客户端断开连接。

TCP状态转换的汇总图:

为什么是4次挥手?

        因为发送端需要断开连接,接收端也需要断开连接。由确认应答机制,每一次断开连接需要进行两次数据传输。

补充:

CLOSING状态:同时关闭。

        当一端发送了FIN没有收到响应ACK,但是收到对方的FIN(对方收到FIN会发送ACK和FIN),并响应ACK,在收到ACK之前,该端处于CLOSING状态,知道收到ACK,才处于TIME_WAIT状态。

        由于超时重传机制,没有收到ACK一段时间后,会重传FIN,但是超过一定次数还是内有收到ACK会直接断开连接。

        3.5.2 四次挥手TIME_WAIT状态

        主动发起断开连接一端会要进入TIME_WAIT状态。

  • TIME_WAIT状态原因 

        TIME_WAIT状态是一端等待时间,主动发起断开连接,发送完FIN收到ACK后,会处于TIME_WAIT 状态。

有两个作用:

  1. 曾经在数据交互时,有的数据可能阻塞在网络中了,等待历史数据的消散。
  2. 保证最后一次挥手的ACK被对方收到,进而让服务器释放连接资源。

        最后一次挥手发送的ACK可能会阻塞或丢失在网络中,导致服务器不能完全断开连接,即没有释放连接资源。服务器时一对多的,我们需要保证服务器的正常运行。

        假设客户端主动发起的连接,进入TIME_WAIT状态,此时服务器没有收到ACK,由于超时重传机制,会重传FIN,如果仍然没有收到ACK(1种可能,网络状况不好,FIN丢失或者阻塞在网络。另外一种情况,TIME_WAIT等待时间过了,客户端已经断开连接),服务器发送FIN到达一定次数会直接断开连接。

一种现象帮助理解:

        TCP协议规定,主动断开连接的一方处于TIME_WAIT状态,等待两个MSL(报文最大生存时间),才能回到CLOSED状态。

为什么等待两个MSL?

  1. 保证两个传输方向上阻塞再网络里的报文都已经消散。
  2. 保证了最后一个ACK的到达,如果最后一个ACK丢失,服务器重发FIN,客户端等待两个MSL,可以收到重发的FIN。再丢失ACK的概率很小。 
  • TIME_WAIT状态解决办法

为什么要解决?

        服务器端会又大量的连接,如果主动关闭连接,会又大量的连接处于TIME_WAIT状态,需要等待很长时间常能重新绑定,建立连接,这是不合理的。

服务器为什么会主动关闭连接?

        当服务器出现问题,需要重启服务器,客户端不活跃,服务器主动关闭连接等。

可以调用接口:

#include <sys/types.h>
#include <sys/socket.h>

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

作用:允许端口复用。允许IP地址不同端口号相同的socket。

参数:sockfd:套接字

        level:再哪一层

        optname:设置属性

使用:

          3.5.3 四次挥手CLOSE_WAIT状态

        连接由CLOSE_WAIT状态变为LAST_ACK状态,需要应用层调用close关闭套接字。

        如果进程一直处于CLOSE_WAIT状态,说明在应用层的程序中有BUG,没有关闭关闭套接字。

        3.6 滑动窗口

                如果发送一个数据段,都需要等到收到响应ACK后才发送数据的话,这样效率比较低,尤其是数据往返的时间较长的时候。

         于是TCP/IP协议在发送数据时,一次发送多条数据,就可以大大提高性能(其实就是多个段的等待时间重叠在一起了)。

        这样就不需要等待一个应答在发送数据,可以继续发送数据到最大值。

        下一次发送的序号,时所有响应中确认序号的最大值。

滑动窗口大小:

        在发送端是指无需等待确认应答而可以继续发送数据的最大值。在接收端是内核可以一次性可以读取数据的个数。

        滑动窗口的大小取决于:对方接收缓冲区剩余空间大小(对方发送数据报文中)和拥塞窗口的大小(后面介绍)。

        所以滑动窗口的大小并不是固定的,而是动态变化的。

拿发送端举例:对应上图。

        滑动窗口之前的数据,是已经发送并且已经收到应答的数据,

        滑动窗口里的数据,是不需要应答,可以发送的数据。

        滑动窗口之后的数据,是尚未发送的数据。

        在内核中, 发送/接收缓冲区是一个队列,滑动窗口的实现,可以是两个指针,一个指针指向滑动窗口的开始,一个指向末尾,两指针之间的大小就是滑动窗口的大小,移动只需要移动两个指针就好了。

        send将数据拷贝到TCP的发送队列中,内核从发送队列中拿数据。内核将接收的数据放到TCP接收队列中,recv将接收队列的数据拷贝出来。生产者消费者模型。

一次性传多个报文,如果发生丢包,如何让进行重传?这里有两种情况

情况一:数据报到达但是,响应丢了。

  •          这种情况我们不怕,因为有多组数据,会有多个响应。部分ACK丢了不要紧,因为可以通过发送过来的ACK,确认从哪个数据发。
  •         还有可能,响应丢了很多,或者说全丢了,这属于拥塞窗口的情况,后面又介绍。

情况二:数据报直接丢了

  •  这种情况,发送方会收到丢失报文序列的响应,即响应的确认序列号是丢失报文的序列号。后序收到报文的响应不会是响应自身的,而是响应丢失的报文的。
  • 如果连续三次收到相同确认序列号的应答,就会直接将丢失报文重发。
  • 接收端收到后,响应的确认序列号是从接收到数据序列号的下一个。如上图。2001~7000已经收到了,放到TCP内核接收缓冲区了。接收端收到1001后,响应位7001。

连续收到3次相同确认序号的应答,直接重发数据的机制是高速重发机制,也叫快重发。

与超时重传机制的区别:

  • 超时重发没有收到响应一段时间会重发数据。很明显快重发效率更高,拿为什么还需要有超时重发。
  • 当发送报文数小于3时,快重发不起效。

         3.7 流量控制

        为什么要有流量控制?

        接收端处理数据是有限的,如果发送端发得太快,接收缓冲区很快就被打满了,这个时候发送区再发送数据,数据会被丢弃,导致发送端需要重传数据,这样效率不高。

        TCP会根据接收端的处理能力,来决定发送数据的速度,这个机制叫做流量控制。

  • 接收端响应报文的报头中有16位的窗口大小,记录了接收端接收缓冲区剩余空间的大小。
  • 接收端一旦发现自己的接收缓冲区快满了,就会将窗口大小设置成一个更小的值通知发送方。
  • 发送方接收到窗口大小后,会减慢自己的发送速度。
  • 如果接收缓冲区满了,就会将窗口设为0,这个时候发送方就不会发送数据,但是发送方怎么知道什么时候发送数据呢?

两种方法:两种方法是同时运行的。这都是内核做的,与上层无关。

方法一:

        窗口探测,发送端隔一段时间,发送一个窗口探测数据段,让接收端响应回来字节的窗口大小。

方法二:

        窗口更新通知:当接收方可以接收数据,会发送窗口更新通知给发送端。

如果窗口探测多次,接收缓冲区还是满的,发送端可以发送带有PSH标志位的报文给接收端,催进程取数据。如果还是满的,说明是应用层程序有BUG。

        在TCP报文中,有一个16位窗口大小,表示的是接收端,接收缓冲区剩余空间的大小。那么,16位最大数字是65535,接收端接收缓冲区大小只有65535字节吗?

        实际上在TCP报头的选项中,还包含了一个窗口扩大因子M,实际窗口大小是16位窗口大小字段值左移M位。

        3.8 拥塞控制

        网络上有很多计算机,可当前网络比较拥堵。客户端一开始就发送大量报文,但是由于网络拥堵,大量报文阻塞在了网络中,接收端没有收到。发送端通过接收端的应答ACK或者没有收到ACK就知道有大量报文丢失了。如果此时再发送大量报文,会导致网络更加拥堵。

        于是TCP引入慢启动机制,一开始先发少量的数据,摸清网络状态,再决定发多少数据。

  • 此处会引入一个拥塞窗口。
  • 拥塞窗口:发送数据时,发送多少数据可能会导致网络阻塞。
  • 发送开始时,拥塞窗口为1,
  • 每次收到ACK应答,拥塞窗口会增加。
  • 发送数据实际发送滑动窗口等于接收端反馈的窗口大小和拥塞窗口的较小值。

拥塞窗口增长速度时指数级别的,慢启动体现在,开始时值很小,但是增长的速度很快。

  • 此处引入一个慢启动阈值
  • 当拥塞窗口超过阈值时,不再按照指数增长,而是按照线性增长。

  •  当TCP启动开始时,慢启动阈值等于窗口大小的最大值
  • 由于网咯堵塞,超时重发时,慢启动的阈值会变为原来的一半,同时阻塞窗口置为1.

少量的丢包,我们认为是正常的,会触发超时重传机制;大量的丢包,我们就认为是网络阻塞。

当通信开始时,网络吞吐量逐渐上升,随着网络开始阻塞,吞吐量有立刻下降

拥塞控制并完全不能解决网络拥堵问题,只是是TCO想尽快的将数据发送给对方,有尽可能少的造成网络拥堵。

        3.9 延时应答

        当接收数据的主机收到请求后立马返回ACK应答,这个时候返回的窗口(剩余接收缓冲区大小)可能会比较小。TCP为了提高效率,会等待一段时间,再做应答。

        作用是:等待应用层先从接收缓冲区读取数据。应答的窗口更大,发送端下一次可以发送更多数据。

比如:接收缓冲区的大小为1M,一次性收到500k的数据,如果立刻应答,返回的窗口时500k,下一次发送就只能发送500k数据。但是实际上可能应用层处理数据的数据很快,数据在网络中传输也需要时间,处理时间和传输时间快。这种情况下,接收端下一次还可以接收更多的数据。如果接收端等一会再应答,下一次接收的数据会多一点,效率更高。

        窗口越大,网络吞吐量就越大,传输效率就更高。我们的目标是,保证网络不拥塞的情况下传输更多的数据。

        也不是所有的数据包都可以延时应答。

        延时应答方法:

  • 数量限制:接收了N个数据报就应答一次
  • 时间限制:超过最大延时时间,就应答一次。

具体的数量和延时时间,依据操作系统有不同,一般N取2,超时时间取200ms。

        3.10 捎带应答

        如果,两态主机在数据交互时。比如:在进行聊天,如果一台主机A向主机B发送数据,主机B要回复,于是主机B要先发送应答ACK,表示收到数据,再向主机A发送数据。要发送两次,这样比较麻烦。于是TCP为了提高效率,就有了捎带应答。

        捎带应答:允许主机在应答报头ACK后加上数据,一起发送出去。

以上是关于传输层UDP/TCP协议的主要内容,如果未能解决你的问题,请参考以下文章

OSI七层模型与TCP/UDP初识(代码待补充,7.31补充)

TCP/IP 协议图--传输层中的 TCP 和 UDP

TCP/IP 6 TCP与UDP

Linux----网络传输层UDP/TCP

TCP和UDP基本原理

TCP/IP -- 2