【Linux网络编程】第十五弹---传输层深度剖析:端标语分别、UDP协议特性与TCP协议全面分析(含毗连受理、流量控制、拥塞控制等)

[复制链接]
发表于 2025-11-27 18:10:15 | 显示全部楼层 |阅读模式
✨个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux体系编程】【Linux网络编程】

目次

1、传输层 
1.1、再谈端标语
1.1.1、端标语范围分别
1.1.2、熟悉着名端标语
1.1.3、两个标题
1.2、UDP 协议
1.2.1、UDP 协议端格式
1.2.2、UDP 的特点
1.2.3、面向数据报
1.2.4、UDP 的缓冲区
1.2.5、UDP 利用留意事项
1.2.6、基于 UDP 的应用层协议
1.3、TCP 协议
1.3.1、TCP 协议段格式
1.3.2、确认应答(ACK)机制
1.3.3、超时重传机制
1.3.4、毗连受理机制
1.3.5、明白 TIME_WAIT 状态
1.3.6、办理 TIME_WAIT 状态引起的 bind 失败 
1.3.7、明白 CLOSE_WAIT 状态
1.3.8、16位窗口巨细
1.3.9、滑动窗口
1.3.10、流量控制
1.3.11、拥塞控制
1.3.12、耽误应答
1.3.13、捎带应答
1.3.14、面向字节流
1.3.15、粘包标题
1.3.16、TCP 非常环境
1.3.17、TCP 小结
1.3.18、TCP/UDP 对比
1.3.19、用 UDP 实现可靠传输(经典口试题)


1、传输层 

   负责数据可以大概从发送端传输吸取端.
  

1.1、再谈端标语

端标语(Port) 标识了一个主机上举行通讯的差别的应用步调;

在 TCP/IP 协议中, 用 "源 IP", "源端标语", "目的 IP", "目的端标语", "协议号" 如许一个五元组来标识一个通讯(可以通过 netstat -n 检察); 

1.1.1、端标语范围分别



  • 0 - 1023: 着名端标语(Well-Know Port Number), HTTP, FTP, SSH 等这些广为利用的应用层协议, 他们的端标语都是固定的.
  • 1024 - 65535: 利用体系动态分配的端标语. 客户端步调的端标语, 就是由利用体系从这个范围分配的.
1.1.2、熟悉着名端标语

有些服务器黑白经常用的, 为了利用方便, 人们约定一些常用的服务器, 都是用以下这些固定的端标语:


  • ssh 服务器, 利用 22 端口
  • ftp 服务器, 利用 21 端口
  • telnet 服务器, 利用 23 端口
  • http 服务器, 利用 80 端口
  • https 服务器, 利用 443
实行下面的下令, 可以看到着名端标语
  1. cat /etc/services # 查看文件内容
  2. vim /etc/services # 编辑文本文件
复制代码

留意:我们本身写一个步调利用端标语时, 要避开这些着名端标语. 
1.1.3、两个标题

1.一个进程是否可以 bind 多个端标语?
   是的,一个进程可以bind多个端标语
  2.一个端标语是否可以被多个进程 bind? 
   在一样平常环境下,一个端标语不可以被多个进程bind
  

1.2、UDP 协议

   UDP协议的全称是User Datagram Protocol,中文名是用户数据报协议
  1.2.1、UDP 协议端格式




  • 16 位 UDP 长度, 体现整个数据报(UDP 首部+UDP 数据)的最大长度;
  • 如果校验和堕落, 就会直接抛弃;
  1、UDP的报头是一个结构体!
  2、怎样将报头和有用载荷举行分离(封装)? 先形貌在构造! 
  3、怎样将有用载荷举行分用?利用结构体指针解引用成员变量!
  

进一步深刻明白报文:
   OS内大概存在大量的报文 - 正在被向上和向下交付 -> OS要对报文举行各种管理 -> 先形貌在构造! 
  

1.2.2、UDP 的特点

UDP 传输的过程类似于寄信.


  • 无毗连: 知道对端的 IP 和端标语就直接举行传输, 不必要创建毗连;
  • 不可靠: 没有确认机制, 没有重传机制; 如果由于网络故障该段无法发到对方,UDP 协议层也不会给应用层返回任何错误信息;
  • 面向数据报: 不可以大概机动的控制读写数据的次数和数目;
1.2.3、面向数据报

   应用层交给 UDP 多长的报文, UDP 原样发送, 既不会拆分, 也不会集并;
  用 UDP 传输 100 个字节的数据:


  • 如果发送端调用一次 sendto, 发送 100 个字节, 那么吸取端也必须调用对应的一次 recvfrom, 吸取 100 个字节; 而不能循环调用 10 次 recvfrom, 每次吸取 10 个字节;
1.2.4、UDP 的缓冲区



  • UDP 没有真正意义上的 发送缓冲区. 调用 sendto 会直接交给内核, 由内核将数据传给网络层协议举行后续的传输动作;
  • UDP 具有吸取缓冲区. 但是这个吸取缓冲区不能包管收到的 UDP 报的次序和发送 UDP 报的次序划一; 如果缓冲区满了, 再到达的 UDP 数据就会被抛弃;
UDP 的 socket 既能读, 也能写, 这个概念叫做 全双工
1.2.5、UDP 利用留意事项



  • 我们留意到, UDP 协议首部中有一个 16 位的最大长度. 也就是说一个 UDP 能传输的数据最大长度是 64K(包罗 UDP 首部).
  • 然而 64K 在当今的互联网环境下, 是一个非常小的数字.
  • 如果我们必要传输的数据凌驾 64K, 就必要在应用层手动的分包, 多次发送, 并在吸取端手动拼装;
1.2.6、基于 UDP 的应用层协议



  • NFS: 网络文件体系
  • TFTP: 简单文件传输协议
  • DHCP: 动态主机设置协议
  • BOOTP: 启动协议(用于无盘装备启动)
  • DNS: 域名剖析协议
固然, 也包罗你本身写 UDP 步调时自界说的应用层协议;
1.3、TCP 协议

TCP 全称为 "传输控制协议(Transmission Control Protocol"). 人如其名, 要对数据的传输举行一个具体的控制;
1.3.1、TCP 协议段格式





  • 源/目的端标语: 体现数据是从哪个进程来, 到哪个进程去;
  • 32 位序号/32 位确认号: 反面具体讲;
  • 4 位 TCP 报头长度: 体现该 TCP 头部有多少个 32 位 bit(有多少个 4 字节 [0, 15] ); 以是TCP 头部最大长度是 15(2^4 - 1) * 4 = 60
  x * 4 = 20 x = 5,因此TCP协议4位首部长度为0101
  

  • 6 位标记位:

    • URG: 告急指针是否有用
    • ACK: 确认号是否有用
    • PSH: 提示吸取端应用步调立刻从 TCP 缓冲区把数据读走
    • RST: 对方要求重新创建毗连; 我们把携带 RST 标识的称为复位报文段 
    • SYN: 哀求创建毗连; 我们把携带 SYN 标识的称为同步报文段
    • FIN  : 关照对方, 本端要关闭了, 我们称携带 FIN 标识的为竣事报文段

  • 16 位窗口巨细: 反面再说
  • 16 位校验和: 发送端添补, CRC 校验. 吸取端校验不通过, 则以为数据有标题. 此
    处的查验和不光包罗 TCP 首部, 也包罗 TCP 数据部门.
  • 16 位告急指针: 标识哪部门数据是告急数据;
  • 40 字节头部选项: 暂时忽略;
1.3.2、确认应答(ACK)机制


TCP通讯模式
为什么要有两个序列号呢?
   一端在应答的同时大概也在传送数据,因此必要利用两个序列号!
  

SYN:

确认应答(ACK)
 

TCP 将每个字节的数据都举行了编号. 即为序列号. 
怎样明白序列号?
   序列号可以当做发送缓冲区数组的下标!
   

每一个 ACK 都带有对应简直认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从那边开始发. 
1.3.3、超时重传机制




  • 主机 A 发送数据给 B 之后, 大概由于网络拥堵等缘故原由, 数据无法到达主机 B;
  • 如果主机 A 在一个特定时间隔断内没有收到 B 发来简直认应答, 就会举行重发
但是, 主机 A 未收到 B 发来简直认应答, 也大概是由于 ACK 丢失了; 

因此主机 B 会收到很多重复数据. 那么 TCP 协议必要可以大概辨认出那些包是重复的包, 而且把重复的抛弃掉.
这时间我们可以利用前面提到的序列号, 就可以很轻易做到去重的结果.
那么,超时的时间怎样确定? 


  • 最抱负的环境下, 找到一个最小的时间, 包管 "确认应答肯定能在这个时间内返回".
  • 但是这个时间的黑白, 随着网络环境的差别, 是有差异的.
  • 如果超时时间设的太长, 会影响团体的重传服从;
  • 如果超时时间设的太短, 有大概会频仍发送重复的包;
TCP 为了包管无论在任何环境下都能比力高性能的通讯, 因此会动态盘算这个最大超时时间.


  • Linux 中(BSD Unix 和 Windows 也是云云), 超时以 500ms 为一个单位举行控制, 每次判定超时重发的超时时间都是 500ms 的整数倍.
  • 如果重发一次之后, 仍然得不到应答, 期待 2*500ms 后再举行重传.
  • 如果仍然得不到应答, 期待 4*500ms 举行重传. 依次类推, 以指数情势递增.
  • 累计到肯定的重传次数, TCP 以为网络大概对端主机出现非常, 逼迫关闭毗连.
1.3.4、毗连受理机制

在正常环境下, TCP 要颠末三次握手创建毗连, 四次挥手断开毗连!


服务端状态转化:


  • [CLOSED -> LISTEN] 服务器端调用 listen 后进入 LISTEN 状态, 期待客户端毗连;
  • [LISTEN -> SYN_RCVD] 一旦监听到毗连哀求(同步报文段), 就将该毗连放入内核期待队列中, 并向客户端发送 SYN 确认报文.
  • [SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端简直认报文, 就进入ESTABLISHED 状态, 可以举行读写数据了.
  • [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭毗连(调用 close), 服务器会收到竣事报文段, 服务器返回确认报文段并进入 CLOSE_WAIT;
  • [CLOSE_WAIT -> LAST_ACK] 进入 CLOSE_WAIT 后分析服务器准备关闭毗连(必要处理惩罚完之前的数据); 当服务器真正调用 close 关闭毗连时, 会向客户端发送FIN, 此时服务器进入 LAST_ACK 状态, 期待末了一个 ACK 到来(这个 ACK 是客户端确认收到了 FIN)
  • [LAST_ACK -> CLOSED] 服务器收到了对 FIN 的 ACK, 彻底关闭毗连.
客户端状态转化: 


  • [CLOSED -> SYN_SENT] 客户端调用 connect, 发送同步报文段;
  • [SYN_SENT -> ESTABLISHED] connect 调用乐成, 则进入 ESTABLISHED 状态, 开始读写数据;
  • [ESTABLISHED -> FIN_WAIT_1] 客户端主动调用 close 时, 向服务器发送竣事报文段, 同时进入 FIN_WAIT_1;
  • [FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对竣事报文段简直认, 则进入 FIN_WAIT_2, 开始期待服务器的竣事报文段;
  • [FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的竣事报文段, 进入TIME_WAIT, 并发出 LAST_ACK;
  • [TIME_WAIT -> CLOSED] 客户端要期待一个 2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入 CLOSED 状态.
RST标记位:
   毗连重置标记位要求对方重新创建毗连; 我们把携带 RST 标识的称为复位报文段 
  

shutdown()
   关闭文件形貌符所关联的文件或套接字(可加选项:关闭读,写,读写)! 
  1. #include <sys/socket.h>
  2. int shutdown(int sockfd, int how);
复制代码
参数


  • sockfd:这是一个文件形貌符,它标识了一个已打开的文件或套接字。
  • how:这个参数指定了关闭的方式,它决定了哪些方向的通讯将被关闭。how 参数可以取以下三个值之一:

    • SHUT_RD(0)关闭读利用,即不再吸取数据。
    • SHUT_WR(1)关闭写利用,即不再发送数据,但可以继续吸取数据(对于TCP套接字而言,这通常会导致对方收到一个EOF标记)。
    • SHUT_RDWR(2):同时关闭读和写利用。

返回值


  • 乐成时,shutdown() 返回0。
  • 失败时,返回-1,并设置 errno 以指示错误缘故原由。

下图是 TCP 状态转换的一个汇总: 



  • 较粗的虚线体现服务端的状态厘革环境;
  • 较粗的实线体现客户端的状态厘革环境;
  • CLOSED 是一个假想的起始点, 不是真实状态; 
创建毗连,为什么要三次握手?
   1、验证全双工(双方都具备发送和吸取本领) --- 验证网络的连通性
  2、创建双方的通讯意愿(只有双方都同意才可以举行通讯)
  

  • 第一次握手确认了客户端的发送本领和服务器的吸取本领第二次握手确认了服务器的发送本领和客户端的吸取本领(对第一次握手简直认);第三次握手则是对第二次握手简直认,确保双方的毗连都已创建。 
  • 哀求毗连的同时捎带应答
再谈四次挥手

1.3.5、明白 TIME_WAIT 状态

现在做一个测试,起首启动 server,然后用 Ctrl-C 使 server 克制,这时立刻再运行 server, 结果是: 

这是由于:固然 server 的应用步调克制了,但 TCP 协议层的毗连并没有完全断开,因此不能再次监 听同样的 server 端口. 我们用 netstat 下令检察一下: 



  • TCP 协议规定,主动关闭毗连的一方要处于 TIME_ WAIT 状态,期待两个MSL(maximum segment lifetime)的时间后才气回到 CLOSED 状态.
  • 我们利用 Ctrl-C 克制了 server, 以是 server 是主动关闭毗连的一方, 在TIME_WAIT 期间仍然不能再次监听同样的 server 端口;
  • MSL 在 RFC1122 中规定为两分钟,但是各利用体系的实现差别, 在 ubuntu 22.04 上默认设置的值是 60s;
  • 可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 检察 msl 的值;

想一想, 为什么是 TIME_WAIT 的时间是 2MSL? 


  • MSL 是 TCP 报文的最大生存时间, 因此 TIME_WAIT 一连存在 2MSL 的话
  • 就能包管在两个传输方向上的尚未被吸取或迟到的报文段都已经消散(否则服务器立刻重启, 大概会收到来自上一个进程的迟到的数据, 但是这种数据很大概是错误的);
  • 同时也是在理论上包管末了一个报文可靠到达(假设末了一个 ACK 丢失, 那么服务器会再重发一个 FIN. 这时固然客户端的进程不在了, 但是 TCP 毗连还在, 仍然可以重发 LAST_ACK); 
1.3.6、办理 TIME_WAIT 状态引起的 bind 失败 



  • 在 server 的 TCP 毗连没有完全断开之前不允许重新监听, 某些环境下大概是不公道的
  • 服务器必要处理惩罚非常大量的客户端的毗连(每个毗连的生存时间大概很短, 但是每秒都有很大数目的客户端来哀求).
  • 这个时间如果由服务器端主动关闭毗连(好比某些客户端不活泼, 就必要被服务器端主动清算掉), 就会产生大量 TIME_WAIT 毗连.
  • 由于我们的哀求量很大, 就大概导致 TIME_WAIT 的毗连数很多, 每个毗连都会占用一个通讯五元组(源 ip, 源端口, 目的 ip, 目的端口, 协议). 此中服务器的 ip 和端口和协议是固定的. 如果新来的客户端毗连的 ip 和端标语和 TIME_WAIT 占用的链接重复了, 就会出现标题.
利用 setsockopt()设置 socket 形貌符的 选项 SO_REUSEADDR 为 1, 体现允许创建端标语雷同但 IP 地点差别的多个 socket 形貌符

setsockopt() 
  1. #include <sys/types.h>         
  2. #include <sys/socket.h>
  3. int setsockopt(int sockfd, int level, int optname,
  4.     const void *optval, socklen_t optlen);
复制代码
 参数


  • sockfd:套接字形貌符,标识要设置选项的套接字。
  • level:选项地点的协议层。常用的有SOL_SOCKET(套接字层)、IPPROTO_TCP(TCP协议层)、IPPROTO_IP(IP协议层)等。
  • optname:必要设置的选项名称。比方SO_REUSEADDR、SO_KEEPALIVE、SO_RCVBUF、SO_SNDBUF、TCP_NODELAY等。
  • optval:指向包罗选项新值的缓冲区。
  • optlen:optval缓冲区的长度。
选项


  • SO_REUSEADDR:允许重用当地地点和端口。这通常用于服务器步调,以确保纵然服务器步调在重启时也能立刻绑定到雷同的地点和端口。
  • SO_KEEPALIVE:启用TCP毗连的保活机制。这允许TCP毗连在一段时间内没有数据传输时,主动发送保活包以检测毗连是否仍然有用。
  • SO_RCVBUFSO_SNDBUF:分别设置吸取和发送缓冲区的巨细。这可以影响套接字的性能和吞吐量。
  • TCP_NODELAY:禁用Nagle算法。Nagle算法是为了镌汰小数据包的发送次数而计划的,但在某些环境下,禁用它可以进步性能
返回值


  • 如果setsockopt函数调用乐成,则返回0。
  • 如果调用失败,则返回-1,并设置全局变量errno以指示错误范例。
1.3.7、明白 CLOSE_WAIT 状态

以之前写过的 TCP 服务器为例, 我们稍加修改,将 TcpServer.hpp 文件td->_sockfd->Close(); 这个代码解释掉.
我们编译运行服务器. 启动客户端链接, 检察 TCP 状态, 客户端服务器都为ESTABLELISHED 状态, 没有标题.

然后我们关闭客户端步调, 观察 TCP 状态
此时服务器进入了 CLOSE_WAIT 状态, 联合我们四次挥手的流程图, 可以以为四次挥手没有精确完成.
小结: 对于服务器上出现大量的 CLOSE_WAIT 状态, 缘故原由就是服务器没有精确的关闭socket, 导致四次挥手没有精确完成. 这是一个 BUG. 只必要加上对应的 close 即可办理标题.
1.3.8、16位窗口巨细

   16位窗口巨细:吸取端可以大概吸取的数据量,即担当缓冲区剩余空间的巨细!
  

PUH 标记位:指示吸取方应尽快将数据从吸取缓冲区通报给应用步调(让对方尽快处理惩罚数据
URG 标记位:当URG标记位被置为1时,体现告急指针字段有用。告急指针指出在本报文段中的告急数据的末了一个字节(0:正常 1:停息 2:取消)的序号,使吸取方可以知道告急数据的长度和位置,以便优先处理惩罚。
16位窗口巨细吸取缓冲区剩余空间的巨细
16位告急指针标识哪部门数据是告急数据(send()函数第三个参数)

1.3.9、滑动窗口

1.流量控制:在发送方,怎样根据对方的担当本领,发送数据?流量控制,就是通过 滑动窗口实现的!
2.超时重传:凌驾期间以内,已经发送的报文不能被抛弃,而是要生存起来!生存在那边?滑动窗口!
刚才我们讨论了确认应答战略, 对每一个发送的数据段, 都要给一个 ACK 确认应答. 收到 ACK 后再发送下一个数据段. 如许做有一个比力大的缺点, 就是性能较差. 尤其是数据往返的时间较长的时间.

既然如许一发一收的方式性能较低, 那么我们一次发送多条数据, 就可以大大的进步性能(着实是将多个段的期待时间重叠在一起了). 



  • 窗口巨细指的是无需期待确认应答而可以继续发送数据的最大值(对方同步给我的窗口巨细,即对方的担当本领(暂时,后序更正)). 上图的窗口巨细就是 4000 个字节(四个段).
  • 发送前四个段的时间, 不必要期待任何 ACK, 直接发送;
  • 收到第一个 ACK 后, 滑动窗口向后移动, 继续发送第五个段的数据; 依次类推;
  • 利用体系内核为了维护这个滑动窗口, 必要开辟 发送缓冲区 来记载当前尚有哪些数据没有应答; 只有确认应答过的数据, 才气从缓冲区删掉;
  • 窗口越大, 则网络的吞吐率就越高; 

明白滑动窗口:
滑动窗口是TCP协议中实现流量控制和可靠数据传输的一种机制。TCP滑动窗口分为发送窗口和吸取窗口。缓冲器可以视为一个char范例数组维护的,而滑动窗口有开始位置和竣事位置开始位置(win_start)为ACK序列号(ack_seq),竣事位置(win_end)为开始位置 + 16位窗口巨细(win) !
 

如果丢包了呢?
1.最左侧报文丢失


  • 确认序列号(确认序号之前的报文,我已经全部收到了)束缚的规定,滑动窗口左侧不动
  • 快重传 && 超时重传对最左侧报文举行补发

2.中央报文丢失


  • 滑动窗口向右移
  • 转化为最左侧报文丢失
  • 如果吸取方担当本领较强,滑动窗口右侧也会向右移,即滑动窗口巨细大概增大

3.最右侧报文丢失


  • 滑动窗口向右移
  • 转化为最左侧报文丢失
  • 如果吸取方担当本领较强,滑动窗口右侧不会变,即滑动窗口巨细大概减小

那么如果出现了丢包, 怎样举行重传? 这里分两种环境讨论.
环境一: 数据包已经抵达, ACK 被丢了.

这种环境下, 部门 ACK 丢了并没关系, 由于可以通过后续的 ACK 举行确认; 
环境二: 数据包就直接丢了. 



  • 当某一段报文段丢失之后, 发送端会不停收到 1001 如许的 ACK, 就像是在提示发送端 "我想要的是 1001" 一样;
  • 如果发送端主机一连三次收到了同样一个 "1001" 如许的应答, 就会将对应的数据 1001 - 2000 重新发送
  • 这个时间吸取端收到了 1001 之后, 再次返回的 ACK 就是 7001 了(由于 2001 -7000)吸取端着实之前就已经收到了, 被放到了吸取端利用体系内核的吸取缓冲区中;
这种机制被称为 "高速重发控制"(也叫 "快重传").
1.3.10、流量控制

吸取端处理惩罚数据的速率是有限的. 如果发送端发的太快, 导致吸取端的缓冲区被打满, 这个时间如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应.
因此 TCP 支持根据吸取端的处理惩罚本领, 来决定发送端的发送速率. 这个机制就叫做流量控制(Flow Control);


  • 吸取端将本身可以吸取的缓冲区巨细放入 TCP 首部中的 "窗口巨细" 字段, 通过 ACK 端关照发送端;
  • 窗口巨细字段越大, 分析网络的吞吐量越高;
  • 吸取端一旦发现本身的缓冲区快满了, 就会将窗口巨细设置成一个更小的值关照给发送端;
  • 发送端担当到这个窗口之后, 就会减慢本身的发送速率;
  • 如果吸取端缓冲区满了, 就会将窗口置为 0; 这时发送方不再发送数据, 但是必要定期发送一个窗口探测数据段, 使吸取端把窗口巨细告诉发送端.

吸取端怎样把窗口巨细告诉发送端呢?
   追念我们的 TCP 首部中, 有一个 16 位窗口字段,就是存放了窗口巨细信息;
  那么标题来了, 16 位数字最大要现 65535, 那么 TCP 窗口最大就是 65535 字节么?
   实际上, TCP 首部 40 字节选项中还包罗了一个窗口扩大因子 M, 实际窗口巨细是 窗口字段的值左移 M 位
  1.3.11、拥塞控制

固然 TCP 有了滑动窗口这个大杀器, 可以大概高效可靠的发送大量的数据. 但是如果在刚开始阶段就发送大量的数据, 仍然大概引发标题.
由于网络上有很多的盘算机, 大概当前的网络状态就已经比力拥堵. 在不清晰当前网络状态下, 贸然发送大量的数据, 是很有大概引起落井下石的.
办理办法? 
   TCP 引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速率传输数据;
  



  • 此处引入一个概念称为拥塞窗口
  • 发送开始的时间, 界说拥塞窗口巨细为 1;
  • 每次收到一个 ACK 应答, 拥塞窗口加 1;
  • 每次发送数据包的时间, 将拥塞窗口和吸取端主机反馈的窗口巨细做比力, 取较小的值作为实际发送的窗口;
更正滑动窗口巨细:
   滑动窗口巨细 = min(应答窗口,拥塞窗口)
  

  • 由于网络的状态是浮动的,因此拥塞窗口的巨细也一定是浮动的 -> 主机怎么样才气得知,拥塞窗口的靠近巨细应该是多大呢?必须颠末多轮实行,才气知道!
像上面如许的拥塞窗口增长速率, 是指数级别的. "慢启动" 只是指初始时慢(可以渐渐镌汰网络发送,让网络规复), 但是增长速率非常快(我们通讯的过程也要规复起来,中后期增长快).


  • 为了不增长的那么快, 因此不能使拥塞窗口单纯的更加.
  • 此处引入一个叫做慢启动的阈(yu)值
  • 拥塞窗口凌驾这个阈值的时间, 不再按照指数方式增长, 而是按照线性方式增长



  • TCP 开始启动的时间, 慢启动阈值即是窗口最大值;
  • 每次超时重发的时间, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回 1;
  1、少量的丢包, 我们仅仅是触发超时重传; 大量的丢包, 我们就以为网络拥塞;
2、当 TCP 通讯开始后, 网络吞吐量会渐渐上升; 随着网络发生拥堵, 吞吐量会立刻降落;
3、拥塞控制, 归根结底是 TCP 协议想尽大概快的把数据传输给对方, 但是又要克制给网络造成太大压力的折中方案.
  TCP 拥塞控制如许的过程, 就似乎 热恋的感觉!
1.3.12、耽误应答

如果吸取数据的主机立刻返回 ACK 应答, 这时间返回的窗口大概比力小.


  • 假设吸取端缓冲区为 1M. 一次收到了 500K 的数据; 如果立刻应答, 返回的窗口就是 500K;
  • 但实际上大概处理惩罚端处理惩罚的速率很快, 10ms 之内就把 500K 数据从缓冲区斲丧掉了;
  • 在这种环境下, 吸取端处理惩罚还远没有到达本身的极限, 纵然窗口再放大一些, 也能处理惩罚过来;
  • 如果吸取端稍微等一会再应答, 好比期待 200ms 再应答, 那么这个时间返回的窗口巨细就是 1M;
肯定要记得, 窗口越大, 网络吞吐量就越大, 传输服从就越高. 我们的目的是在包管网络不拥塞的环境下只管进步传输服从;
那么全部的包都可以耽误应答么? 肯定也不是;


  • 数目限定: 每隔 N 个包就应答一次;
  • 时间限定: 凌驾最大耽误时间就应答一次;
具体的数目和超时时间, 依利用体系差别也有差异; 一样平常 N 取 2, 超时时间取 200ms;

1.3.13、捎带应答

在耽误应答的根本上, 我们发现, 很多环境下, 客户端服务器在应用层也是 "一发一收"的. 意味着客户端给服务器说了 "How are you", 服务器也会给客户端回一个 "Fine,thank you";
那么这个时间 ACK 就可以搭顺风车, 和服务器回应的 "Fine, thank you" 一起回给客户端

1.3.14、面向字节流

创建一个 TCP 的 socket, 同时在内核中创建一个 发送缓冲区 和一个 吸取缓冲区;


  • 调用 write 时, 数据会先写入发送缓冲区中;
  • 如果发送的字节数太长, 会被拆分成多个 TCP 的数据包发出;
  • 如果发送的字节数太短, 就会先在缓冲区里期待, 比及缓冲区长度差不多了, 大概其他符合的机遇发送出去;
  • 吸取数据的时间, 数据也是从网卡驱动步调到达内核的吸取缓冲区;
  • 然后应用步调可以调用 read 从吸取缓冲区拿数据;
  • 另一方面, TCP 的一个毗连, 既有发送缓冲区, 也有吸取缓冲区, 那么对于这一个毗连, 既可以读数据, 也可以写数据. 这个概念叫做 全双工 
由于缓冲区的存在, TCP 步调的读和写不必要逐一匹配, 比方:


  • 写 100 个字节数据时, 可以调用一次 write 写 100 个字节, 也可以调用 100 次 write, 每次写一个字节;
  • 读 100 个字节数据时, 也完全不必要思量写的时间是怎么写的, 既可以一次read 100 个字节, 也可以一次 read 一个字节, 重复 100 次;
1.3.15、粘包标题

起首要明白, 粘包标题中的 "" , 是指的应用层的数据包.


  • 在 TCP 的协议头中, 没有如同 UDP 一样的 "报文长度" 如许的字段, 但是有一个序号如许的字段.
  • 站在传输层的角度, TCP 是一个一个报文过来的. 按照序号排好序放在缓冲区中.
  • 站在应用层的角度, 看到的只是一勾通续的字节数据.
  • 那么应用步调看到了这么一连串的字节数据, 就不知道从哪个部门开始到哪个部门, 是一个完备的应用层数据包.
那么怎样克制粘包标题呢? 归根结底就是一句话, 明白两个包之间的边界.


  • 对于定长的包, 包管每次都按固定巨细读取即可; 比方上面的 Request 结构, 是固定巨细的, 那么就从缓冲区重新开始按 sizeof(Request)依次读取即可;
  • 对于变长的包, 可以在包头的位置, 约定一个包总长度的字段, 从而就知道了包的竣事位置;
  • 对于变长的包, 还可以在包和包之间利用明白的分隔符(应用层协议, 是步调猿本身来定的, 只要包管分隔符反面正文辩论即可);
思索: 对于 UDP 协议来说, 是否也存在 "粘包标题" 呢?


  • 对于 UDP, 如果还没有上层交付数据, UDP 的报文长度仍然在. 同时, UDP 是一个一个把数据交付给应用层. 就有很明白的数据边界(没有粘包标题).
  • 站在应用层的站在应用层的角度, 利用 UDP 的时间, 要么收到完备的 UDP 报文, 要么不收. 不会出现"半个"的环境.
1.3.16、TCP 非常环境

   1、进程克制: 进程克制会开释文件形貌符, 仍然可以发送 FIN. 和正常关闭没有什么区别.
2、呆板重启: 和进程克制的环境雷同.
3、呆板掉电/网线断开: 吸取端以为毗连还在, 一旦吸取端有写入利用, 吸取端发现毗连已经不在了, 就会举行 reset. 纵然没有写入利用, TCP 本身也内置了一个保活定时器, 会定期扣问对方是否还在. 如果对方不在, 也会把毗连开释.
  别的, 应用层的某些协议, 也有一些如许的检测机制. 比方 HTTP 长毗连中, 也会定期检测对方的状态. 比方 QQ, 在 QQ 断线之后, 也会定期实行重新毗连.
1.3.17、TCP 小结

为什么 TCP 这么复杂? 由于要包管可靠性, 同时又尽大概的进步性能.
可靠性:


  • 校验和
  • 序列号(按序到达)
  • 确认应答
  • 超时重发
  • 毗连受理
  • 流量控制
  • 拥塞控制
进步性能:


  • 滑动窗口
  • 快速重传
  • 耽误应答
  • 捎带应答
其他:


  • 定时器(超时重传定时器, 保活定时器, TIME_WAIT 定时器等)
基于 TCP 应用层协议


  • HTTP
  • HTTPS
  • SSH
  • Telnet
  • FTP
  • SMTP
固然, 也包罗你本身写 TCP 步调时自界说的应用层协议
1.3.18、TCP/UDP 对比

我们说了 TCP 是可靠毗连, 那么是不是 TCP 肯定就优于 UDP 呢? TCP 和 UDP 之间的优点和缺点, 不能简单, 绝对的举行比力


  • TCP 用于可靠传输的环境, 应用于文件传输, 紧张状态更新等场景;
  • UDP 用于对高速传输和及时性要求较高的通讯范畴, 比方, 早期的 QQ, 视频传输等. 别的 UDP 可以用于广播;
归根结底, TCP 和 UDP 都是步调员的工具, 什么机遇用, 具体怎么用, 照旧要根据具体的需求场景去判定.
1.3.19、用 UDP 实现可靠传输(经典口试题)

参考 TCP 的可靠性机制, 在应用层实现类似的逻辑;
比方:


  • 引入序列号, 包管数据次序;
  • 引入确认应答, 确保对端收到了数据;
  • 引入超时重传, 如果隔一段时间没有应答, 就重发数据;
  • ......


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表