传输层协议——TCP

绕不开的TCP之三次握手 在面试过程中,无论是开发还是测试岗位,TCP都是一个绕不开的话题,而谈到TCP,大概率三次握手也会被提及,那应该如何回答这个问题呢?在回答这个问题之前,让我们先预热一波吧。 TCP的定义 TCP协议全称: 传输控制协议, 顾名思义, 就是要对数据的传输进行一定的控制,它是一种面向连接的、可靠的、基于字节流的传输层通信协议。 TCP连接全过程的状态 TCP连接全过程中,客户端及服务端存在的状态如下:... 阅读详情


前言

TCP 全称为 "传输控制协议(Transmission Control Protocol"). ,这种协议是对数据的传输进行一个详细的控制;


一、报文的理解

如果应用层正在进行报文的解析,会不会影响OS从网络中读取报文呢?答案是当然可以
从操作系统对数据的处理来看,它是根据中断机制来进行COU数据的处理的,当处理报文时,会有时钟中断响应来进行进程的调度,而读取报文又会响应对应硬件中断机制,这就意味着操作系统内核上会有大量的报文需要管理

对于管理,永远绕不开:先描述,再组织!

1.1 内核中的数据结构sk_buff

sk_buff 的设计目标是高效管理网络报文的整个生命周期:从网卡接收报文(入口),到经过协议栈各层解析 / 处理(如 TCP 解包、IP 路由),再到最终发送到网卡(出口),或交付给应用程序。

sk_buff 的核心结构成员(简化版)sk_buff 结构复杂(定义在include/linux/skbuff.h),以下是相关的核心字段:

struct sk_buff {
    // 1. 数据缓冲区指针(核心!通过指针偏移管理各层头部)
    unsigned char *head;   // 缓冲区起始地址(分配时固定)
    unsigned char *data;   // 当前层数据的起始地址(随协议层变化)
    unsigned char *tail;   // 当前层数据的结尾地址(数据长度 = tail - data)
    unsigned char *end;    // 缓冲区结束地址(缓冲区大小 = end - head)

    // 2. 链表结构(用于报文队列管理)
    struct sk_buff *next;  // 下一个skb
    struct sk_buff *prev;  // 上一个skb

    // 3. 协议相关信息
    __be16 protocol;       // 上层协议类型(如 ETH_P_IP 表示IP协议)
    struct net_device *dev;// 关联的网络设备(如接收/发送的网卡)

    // 4. 各层协议头部指针(快速访问,避免重复解析)
    struct ethhdr *mac_header;  // 链路层头部(如以太网头)
    struct iphdr *ip_header;    // 网络层头部(如IP头)
    struct tcphdr *tcp_header;  // 传输层头部(如TCP头)

    // 5. 生命周期管理
    atomic_t users;        // 引用计数(0时释放缓冲区)
};

(仅辅助于理解)sk_buff 最精妙的设计是通过 head/data/tail/end 四个指针,在不移动数据的情况下,高效管理各层协议头部和数据。

  1. 缓冲区范围:head 到 end 是内核为该报文分配的内存缓冲区(固定大小),包含所有可能的协议头部(链路层、网络层、传输层)和应用数据。
  2. 当前层数据范围:data 到 tail 是 “当前协议层” 需要处理的数据(随协议层变化)。
  • 以报文接收时的指针变化(从链路层到传输层)
    当网卡收到一个 TCP 报文(以太网帧),sk_buff 的指针变化如下:
  1. 链路层(以太网):
    驱动将以太网帧(含以太网头 + IP 头 + TCP 头 + 应用数据)拷贝到 sk_buff 的缓冲区,此时:
    head = 缓冲区起始(指向以太网头开始)
    data = head(当前处理以太网头)
    tail = head + 帧总长度(指向数据结尾)
    解析以太网头后,内核通过 skb_pull(skb, ETH_HLEN) 调整 data 指针(data += 以太网头长度),跳过以太网头,准备交给 IP 层。
  2. 网络层(IP):
    此时 data 指向 IP 头开始,tail 仍指向数据结尾。
    解析 IP 头后,通过 skb_pull(skb, IP_HLEN) 调整 data 指针(data += IP头长度),跳过 IP 头,准备交给 TCP 层。
  3. 传输层(TCP):
    此时 data 指向 TCP 头开始,tail 指向数据结尾。
    解析 TCP 头后,通过 skb_pull(skb, TCP_HLEN) 调整 data 指针(data += TCP头长度),剩下的 data 到 tail 就是应用数据(最终交付给应用程序)。
    举例:报文发送时的指针变化(从传输层到链路层)

所以网络通信其实就是两个进程通过sk_buff数据结构进行通信!!
在这里插入图片描述

二、TCP协议段格式

//linux内核TCP数据结构
struct tcphdr {
    __be16  source;          // 源端口号(16位,网络字节序)
    __be16  dest;            // 目的端口号(16位,网络字节序)
    __be32  seq;             // 序号(32位,当前报文段第一个字节的序号)
    __be32  ack_seq;         // 确认号(32位,期望接收的下一字节序号,仅当 ACK 标志置位有效)

    __u8    doff;            // 数据偏移(4位,单位为32位字,即 TCP 头部长度 = doff * 4 字节)
    __u8    res1 : 4;        // 保留位(4位,未使用,必须为0)
    __u8    cwr : 1;         // 拥塞窗口减少(CWR,1位,用于拥塞控制)
    __u8    ece : 1;         // ECN 回声(ECE,1位,与 ECN 机制相关)
    __u8    urg : 1;         // 紧急指针有效(URG,1位)
    __u8    ack : 1;         // 确认号有效(ACK,1位,建立连接后通常置位)
    __u8    psh : 1;         // 推送数据(PSH,1位,接收方应立即将数据提交给应用层)
    __u8    rst : 1;         // 重置连接(RST,1位,强制关闭连接)
    __u8    syn : 1;         // 同步序号(SYN,1位,用于建立连接)
    __u8    fin : 1;         // 结束连接(FIN,1位,用于终止连接)

    __be16  window;          // 窗口大小(16位,接收方的接收窗口,用于流量控制)
    __be16  check;           // 校验和(16位,用于校验 TCP 头部和数据的完整性)
    __be16  urg_ptr;         // 紧急指针(16位,仅当 URG 置位有效,指示紧急数据在报文中的偏移)
};

  • 源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去;
  • 32 位序号/32 位确认号: 详见 2.1
  • 16 位窗口大小: 详见 2.2
  • 4 位 TCP 报头长度: 每一位的权值表示该 TCP 头部有多少个 32 位 bit(有多少个 4 字节); 所以TCP 头部最大长度是 15 * 4 = 60,并且TCP最小为20。每位报头长度为20+4*n
  • 16 位校验和: 发送端填充, CRC 校验. 接收端校验不通过, 则认为数据有问题. 此
    处的检验和不光包含 TCP 首部, 也包含 TCP 数据部分. )仅作了解(
  • 16 位紧急指针: 标识哪部分数据是紧急数据;
  • 40 字节头部选项: 暂时忽略;
  • 6 位标志位:
    ○ URG: 紧急指针是否有效
    ○ ACK: 确认号是否有效
    ○ PSH: 提示接收端应用程序立刻从 TCP 缓冲区把数据读走
    ○ RST: 对方要求重新建立连接; 我们把携带 RST 标识的称为复位报文段
    ○ SYN: 请求建立连接; 我们把携带 SYN 标识的称为同步报文段
    ○ FIN: 通知对方, 本端要关闭了, 我们称携带 FIN 标识的为结束报文段

报头和有效载荷的分离:读取前20个字节(协议标准,必须要有),再提取报头长度,将首部长度×4后减去20,再提取这个长度,至此得到并移走处理报头加选项,剩下的就是数据部分了
相比于UDP协议这里是没有报文数据长度大小的,因此操作系统是不知道TCP的整个报文长度的,它将报头和有效载荷(也就是报文数据)分离后,就不管这个数据了,将它放到自己的缓冲区后并在合适时机提交到上层应用层,让应用层来处理这个数据,这就是TCP的特性称为面向字节流的原因!!

2.1 序号

A是怎么确定B收到了消息呢?当A问B吃饭了没,B给A回答说吃过了,那么A就确定B吃过了。这一来一回就保证了从A到B的可靠性。因此对于TCP可靠性性质来说具有应答就是可靠的(即历史消息具有百分百可靠性),但对于最新的报文来说是没有应答的就意味着可靠性没法保证。这种机制被称为确认应答(双方不对应答做应答)

对于TCP来说,一次发送多个报文无疑是更有性价比的,也可以说TCP 倾向于批量发送,以减少头部对带宽的浪费。

  • 若一次只发送一个小报文(如仅 1 字节数据),头部可能占比 95% 以上(20 字节头部 + 1 字节数据),有效数据传输率极低。
  • 若一次发送多个报文(或合并多个小数据为较大的报文),头部总开销占比会显著降低。例如,10 个报文的总头部为 200 字节,若每个携带 1000 字节数据,总数据量 10000 字节,头部占比仅 2%,有效利用率大幅提升。

对于TCP来说,当发送多个报文并确认应答的时候,此时TCP头部的序号和确认序号就可以发挥作用了。(确认序号=序号+1)

在看以下图片的时候,请带着这样子的理解:每一个箭头其实都是TCP报文,至少也是一个TCP报头!而所谓的数字就是报头中的序号位段
在这里插入图片描述

应答的话只要有一个序号结构就行了啊,为什么在TCP报头中会存在序号和确认序号两个序号结构呢?
通信是双方的,A给B发消息,B给A应答的时候,可以捎带着自己的数据给A,这种应答叫做捎带应答。这样结合在一起,可以批量化发送报文,通信的效率就更高了。

2.2 窗口

当对端的TCP接受缓冲区满了该怎么办呢?继续发?然后让对方丢弃自己发的报文?这样做当然不行,面临效率低下且占用资源的问题,此时TCP报头中的16位滑动窗口就可以发挥作用了。
只需要让TCP按需按量发送,即知道对端的接受缓冲区大小,把自己缓冲区剩余大小添加到16位窗口大小,这种机制称为流量控制(作用是合理发送数据,主要站在效率角度,考虑了可靠性)

2.3 标志位

标志位本质上就是报头上比特位,为什么要有标志位呢?

TCP发送一次报文只是为了传数据嘛?传数据前也得建立连接或者断开连接,有多个客户端给服务器发送消息,根据业务类型的不同和确认是那种方式,于是就衍伸出标志位的存在来表明本次报文是干嘛的!

这里主要通过介绍三次握手引出标志位:TCP 是双向通信协议,双方(客户端和服务器)都需要确认 “自己能发送数据,且对方能接收数据”。三次握手通过三步交互,完整验证双向可达性:

  1. 第一次握手(客户端 → 服务器):
    客户端发送 SYN 报文(syn=1),携带客户端初始序号 seq=x,表示 “我(客户端)想建立连接,我的初始序号是 x,你能收到吗?”。
    → 服务器收到后,确认 “客户端能发送,我(服务器)能接收”。
  2. 第二次握手(服务器 → 客户端):
    服务器回复 SYN+ACK 报文(syn=1, ack=1),携带服务器初始序号 seq=y 和对客户端的确认号 ack=x+1,表示 “我收到了你的请求(x 已收到,下次请发 x+1),我的初始序号是 y,你能收到吗?”。
    → 客户端收到后,确认 “服务器能发送,我(客户端)能接收”,且 “服务器已理解我的初始序号”。
  3. 第三次握手(客户端 → 服务器):
    客户端回复 ACK 报文(ack=1),确认号 ack=y+1,表示 “我收到了你的初始序号 y(下次请发 y+1),连接可以建立了”。
    → 服务器收到后,确认 “客户端已理解我的初始序号,且能正确回复”。
    通过这三步,双方最终确认:客户端→服务器和服务器→客户端的双向通信链路都能正常工作。

在三次握手中有个隐形条件:时间!这也是为什么画图要画成斜杠式的原因。并且必须明确每一条斜杠线其实就是携带对应标志位的一个报文!!
在这里插入图片描述
在客户端方面它执行完发收发这三步就确定自己建立连接了,而服务器端则是收发收,那么最后一步的ACK双方是不知道是否成功的,这就导致了连接建立是否成功认知不一致问题
因此当完成三次握手但并未建立连接,客户端给服务器发带数据的报文的时候,服务器并不清楚客户端这是要干嘛,于是服务器就会发送带RST标志位的报文给客户端以求重新建立连接。通信过程中出现任何问题都可以通过在报文中设置RST标志位来重置连接。

三、TCP协议中具体机制

在上面的协议格式中都或多或少通过协议机制来讲述报头的每个数据结构定义的目的。以下将会具体来说明这些机制的作用。

3.1 确认应答(ACK)机制

在这里插入图片描述
TCP 将每个字节的数据都进行了编号. 即为序列号. 每一个 ACK 都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发.

我们可以把序号暂时理解成一维数组,数组的最后一位下标就是序号
在这里插入图片描述

序号的作用

  1. 确认应答
  2. 按序到达
  3. 去重

丢包

在特定的时间间隔内,收不到应答,判定为报文丢了-》收不到应答&&超时(等待时间式随情况变化的)

在这里插入图片描述

  • 主机 A 发送数据给 B 之后, 可能因为网络拥堵等原因, 数据无法到达主机 B;
  • 如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会进行重发(如果对方已经收到了,重发后则根据序号去重);

但是, 主机 A 未收到 B 发来的确认应答, 也可能是因为 ACK 丢失了;
在这里插入图片描述
在很多教材和说明里面这种情况也被称为丢包,但是发送方没有收到ACK只能意味数据可能丢失对方没收到,无法百分百保证对方收到消息,用无法保证可靠性来形容这种情况更为合适!!

附:超时时间的确定
  • 最理想的情况下, 找到一个最小的时间, 保证 “确认应答一定能在这个时间内返
    回”.
  • 但是这个时间的长短, 随着网络环境的不同, 是有差异的.
  • 如果超时时间设的太长, 会影响整体的重传效率;
  • 如果超时时间设的太短, 有可能会频繁发送重复的包;

TCP 为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算(探索)这个最大超时时间.

  • Linux 中(BSD Unix 和 Windows 也是如此), 超时以 500ms 为一个单位进行控
    制, 每次判定超时重发的超时时间都是 500ms 的整数倍.
  • 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.
  • 如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.
  • 累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接.

3.2 连接管理机制(理解为什么需要连接的重要部分)

在正常情况下, TCP 要经过三次握手建立连接, 四次挥手断开连接
其中操作系统发消息和我们connect等函数调用是分层的

在这里插入图片描述
服务端状态转化:

  • [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 状态.

等待2MSL的原因

  1. 就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服
    务器立刻重启,对应报文还在网络中传输, 可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的);
  2. 同时也是在理论上保证最后一个报文可靠到达(假设最后一个 ACK 丢失, 那么
    服务器会再重发一个 FIN. 这时虽然客户端的进程不在了, 但是 TCP 连接还在, 仍然可以重发 LAST_ACK);

TIME_WAIT 状态会引起 bind error ,站在应用角度,我们既要TIME_WAIT又要能够立即重启。
使用 setsockopt()设置 socket 描述符的 选项 SO_REUSEADDR 为 1, 表示允许创建端口号相同但 IP 地址不同的多个 socket 描述符
在这里插入图片描述

理解确认连接

为什么要进行三次握手????
男女朋友->成为夫妻需要满足

  1. 双方愿意
  2. 父母等外部条件满足

三次握手的原因(以客户端向服务器发为走向): 1.以最小成本,百分百确定双方有通信意愿。 第一次握手,服务器知道自己能收消息,但不知道自己能发消息,客户端什么也不知道。第二次握手客户端知道自己能收发消息,而服务器依旧只能知道自己收消息。第三次握手双方都确定有了自己收发消息的能力 2.可以验证网络是通畅的,确认双方都有全双工的能力(以最短的方式,验证全双工)

此外三次握手也是四次握手,在第二次握手的时候,服务端执行了两个动作,ACK和SYN,只不过服务端无脑答应客户端连接请求,携带ACK的报文同时携带了SYN,捎带应答使四次握手压缩为三次握手。

断开连接:

进行四次挥手活动,建立断开连接的共识。在应用层的表现就是ciose网络文件

那么为什么断开连接不能像三次握手那样把FIN和ACK压缩为一个呢?因为在大部分情况下,当客户端想要断开连接的时候,服务端不一定想要断开连接!它的发送缓冲区可能还有数据,因此当客户端断开连接的时候,可能只是关闭了文件的写,而读可能依旧开着,执行单双工模式。

先发起断开连接的一端,最后会进入TIME_WAIT状态,即使完成四次挥手

3.3 滑动窗口

滑动窗口的本质是流量控制,TCP传输时面向字节流的

刚才我们讨论了确认应答策略, 对每一个发送的数据段, 都要给一个 ACK 确认应答. 收到 ACK 后再发送下一个数据段. 这样做有一个比较大的缺点, 就是性能较差. 尤其是数据往返的时间较长的时候.
在这里插入图片描述
既然这样一发一收的方式性能较低, 那么我们一次发送多条数据, 就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了).
在这里插入图片描述
窗口大小指的是无需等待确认应答而可以继续发送数据的最大值. 上图的窗口
大小就是 4000 个字节(四个段).

  • 发送前四个段的时候, 不需要等待任何 ACK, 直接发送;
  • 收到第一个 ACK 后, 滑动窗口向后移动, 继续发送第五个段的数据; 依次类推;
  • 操作系统内核为了维护这个滑动窗口, 需要开辟 发送缓冲区 来记录当前还有哪
    些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉;
  • 窗口越大, 则网络的吞吐率就越高;

细节解释理解:

滑动窗口的存在我们可以理解为在发送缓冲区这个一个数组中的两个下标组成的闭合区域,窗口左边的区域数据我们可以确定为已经发送的数据(无效数据),由此便可以不需要可以删除清空数据,右边的区域则是等待发送或者无数据区域又或者两者皆有。
序号发送的轮次依次增大,意味滑动窗口基本向右滑动(宏观),而滑动的本质就是下标改变。
在这里插入图片描述

滑动窗口的大小由谁决定呢?由对方接收的能力决定,通过收到对方报文win大小来决定自己的窗口大小

而丢包问题的底层解决基础就是滑动窗口
解决丢包问题有两个机制:超时重传和快重传,其中超时重传为兜底。

那么如果出现了丢包, 如何进行重传? 这里分两种情况讨论.
情况一: 数据包已经抵达, ACK 被丢了.
这种情况下, 部分 ACK 丢了并不要紧, 因为可以通过后续的 ACK 进行确认(至于接受方怎么“感知丢失”,则是通过维护一个关键变量 rcv_nxt(Next Receive Sequence Number,下一个期望接收的字节序号);
在这里插入图片描述

情况二: 数据包就直接丢了.

  • 当某一段报文段丢失之后, 发送端会一直收到 1001 这样的 ACK, 就像是在提醒
    发送端 “我想要的是 1001” 一样;
  • 如果发送端主机连续三次收到了同样一个 “1001” 这样的应答, 就会将对应的数据 1001 - 2000 重新发送;
  • 这个时候接收端收到了 1001 之后, 再次返回的 ACK 就是 7001 了(因为 2001 - 7000)接收端其实之前就已经收到了, 被放到了接收端操作系统内核的接收缓冲区中;
    在这里插入图片描述

这种机制被称为 “高速重发控制”(也叫 “快重传”).

假设场景:发送方依次发送 4 个数据包 P1(序号 100-199)、P2(200-299)、P3(300-399)、P4(400-499),其中 P2 在传输中丢失。
步骤 1:接收方收到失序数据包,发送重复 ACK
接收方首先收到 P1(序号 100-199),此时期望序号 rcv_nxt (内核中维护的一个数据结构)更新为 200,发送 ACK1(确认号 = 200)。
由于 P2 丢失,接收方接下来收到 P3(序号 300-399),其序号(300)> 期望序号(200),判定为 “失序”。
接收方暂存 P3(不提交给应用层,等待 P2 补全),rcv_nxt 仍保持 200。
发送重复 ACK2(确认号 = 200),告知发送方 “我需要 200 开始的数据包,300-399 已收到但不连续”。
接收方继续收到 P4(序号 400-499),仍失序(400 > 200),再次发送重复 ACK3(确认号 = 200)。
若发送方继续发送 P5(500-599),接收方收到后发送重复 ACK4(确认号 = 200)。
步骤 2:发送方累计重复 ACK,触发快速重传
发送方收到 ACK2(重复,确认号 = 200)→ 计数 = 1。
收到 ACK3(重复,确认号 = 200)→ 计数 = 2。
收到 ACK4(重复,确认号 = 200)→ 计数 = 3,达到阈值。
发送方推断:“接收方连续 3 次需要 200,说明 P2(200-299)已丢失”,立即重传 P2(无需等待超时计时器)。
步骤 3:接收方确认重传的数据包,恢复正常传输
接收方收到重传的 P2(200-299),此时 P2、P3、P4、P5 形成连续序号(100-599)。
接收方更新 rcv_nxt 为 600,将所有数据提交给应用层,发送 ACK5(确认号 = 600)。
发送方收到 ACK5,确认 P2 及后续数据包均已被接收,重置重复 ACK 计数,继续正常发送数据。

3.4 拥塞控制

网络丢包问题的多少所造成的结论也是不同的,当出现大面积丢包的时候,这个问题就成为网络拥塞问题。
在网络硬件无障碍的前提下,TCP除了考虑双方主机问题,也考虑了网络问题。

虽然 TCP 有了滑动窗口这个大杀器, 能够高效可靠的发送大量的数据. 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题.
因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵. 在不清楚当前网络状态下, 贸然发送大量的数据, 是很有可能引起雪上加霜的.
TCP 引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据
在这里插入图片描述

  • 此处引入一个概念称为拥塞窗口
  • 发送开始的时候, 定义拥塞窗口大小为 1;
  • 每次收到一个 ACK 应答, 拥塞窗口加 1;
  • 每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较
    小的值作为实际发送的窗口;

像上面这样的拥塞窗口增长速度, 是指数级别的. “慢启动” 只是指初使时慢, 但是增长速度非常快.

  • 为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍.
  • 此处引入一个叫做慢启动的阈值
  • 当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增
    长,目的是不断探测网络新的拥塞的值。
    在这里插入图片描述
  • 当 TCP 开始启动的时候, 慢启动阈值等于窗口最大值;
  • 在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回 1;
    少量的丢包, 我们仅仅是触发超时重传; 大量的丢包, 我们就认为网络拥塞;
    当 TCP 通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降;拥塞控制, 归根结底是 TCP 协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案

不是由滑动窗口来决定传输数据多少嘛?滑动窗口大小=对方接受能力大小。因此为了支持上面的拥塞控制算法,引入了拥塞窗口
拥塞窗口:一个临界值,值以内,网络大概率不拥堵,值以上,网络可能拥堵
滑动窗口=min(对方win,拥塞窗口)!!谁小谁是主要矛盾

3.5 延迟应答

延迟应答
如果接收数据的主机立刻返回 ACK 应答, 这时候返回的窗口可能比较小.

  • 假设接收端缓冲区为 1M. 一次收到了 500K 的数据; 如果立刻应答, 返回的窗口
    就是 500K;
  • 但实际上可能处理端处理的速度很快, 10ms 之内就把 500K 数据从缓冲区消费
    掉了;
  • 在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也
    能处理过来;
  • 如果接收端稍微等一会再应答, 比如等待 200ms 再应答, 那么这个时候返回的
    窗口大小就是 1M; 一定要记得, 窗口越大, 网络吞吐量就越大, 传输效率就越高. 我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;
    那么所有的包都可以延迟应答么? 肯定也不是;
  • 数量限制: 每隔 N 个包就应答一次;
  • 时间限制: 超过最大延迟时间就应答一次;
    在这里插入图片描述

具体的数量和超时时间, 依操作系统不同也有差异; 一般 N 取 2, 超时时间取 200ms;

3.6 异常问题

  1. 进程终止: 进程终止会释放文件描述符, 仍然可以发送 FIN. 和正常关闭没有什么区别.
  2. 机器重启: 和进程终止的情况相同.
  3. 机器掉电/网线断开: 接收端认为连接还在, 一旦接收端有写入操作, 接收端发现连接已经不在了, 就会进行 reset. 即使没有写入操作, TCP 自己也内置了一个保活定时器, 会定期询问对方是否还在. 如果对方不在, 也会把连接释放.
  4. 另外, 应用层的某些协议, 也有一些这样的检测机制. 例如 HTTP 长连接中, 也会定期检测对方的状态. 例如 QQ, 在 QQ 断线之后, 也会定期尝试重新连接.

TCP的TIME_WAIT状态 1. TIME_WAIT状态 主动关闭方在收到被动关闭方的FIN包后并返回ACK后,会进入TIME_WAIT状态,TIME_WAIT状态又称2MSL状态,每个TCP连接都必须有一个最大报文段生存时间MSL,在网络传输中超过这个时间的报文段将被丢弃。当TCP连接发起一个主动关闭,并发出最后一个ACK时,必须在TIME_WAIT状态停留两倍MSL时间,在2MSL等待期间,定义这个连接的插口(客户端IP... 阅读详情

相关推荐

传输层、TCP协议的通俗解释

TCP和UDP作用在运输层,他们将应用层传递下来的数据按照TCP、UDP自己的协议格式封装起来,再传给网络层,由网络层的IP协议封装成IP数据报的形式,然后通过网络、路由器转发等操作再传输到另一台通信主机,主机收到数据后解封装,并交给传输层处理,传输层再解封装交给应用层处理。

char_xidian的博客 4839

【网络】传输层协议——TCP协议(初阶)

TCP 是面向连接的运输层协议。应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。在传送数据完毕后,必须释放已经建立的 TCP 连接每一条 TCP 连接只能有两个端点,每一条 TCP 连接只能是点对点的(一对一)TCP 提供可靠交付的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达TCP 提供全双工通信。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接受缓存,用来临时存放双向通信的数据面向字节流。

2301_80224556的博客 9490

vtk相机_分别用 VTK 体绘制和面绘制来实现医学图像三维重建;

序言,VTK介绍:VTK 全称为 The Visualization Toolkit (可视化工具),是一个开源、跨平台、自由获取、支持并行计算的图形应用函数;拥有3D 渲染的最新工具、提供3D交互模式以及2D绘图等。VTK 包含一个C++类库,目前提供了众多语言接口,例如 Java、Python、TCL;在三维函数库OpenGL 的基础上采用面向对象设计方法发展起来图形学基本概念和数据...

weixin_39665302的博客 687

【计算机网络】TCP协议超详细讲解

TCP协议广泛应用于可靠性要求较高的应用场景,如网页浏览、文件传输、电子邮件等。它提供了可靠的数据传输和流控制机制,能够确保数据的完整性和有序性。然而,由于TCP协议在传输过程中引入了较多的控制信息,因此相比于UDP协议,TCP的传输速度较慢。

云泽野の编程日记 1万+

Cortex-M TrustZone实战:从硬件隔离到安全交互的嵌入式开发指南

在嵌入式系统开发中,硬件安全隔离是构建可信执行环境(TEE)的核心技术。其原理是通过处理器硬件机制,将系统资源划分为安全与非安全域,实现内存、外设和代码的强制访问控制。这项技术的核心价值在于,它能在单一芯片上为资源受限的物联网(IoT)设备、智能传感器等提供芯片级的安全基础,无需依赖外置安全元件,从而降低BOM成本并简化设计。典型的应用场景包括保护设备密钥、实现安全启动、构建安全服务(如加密、密钥管理)以供应用程序调用。本文聚焦于Arm Cortex-M系列微控制器上的TrustZone技术实现,针对开发中

weixin_42639246的博客 300

手把手教你安装 Vivado2019.2(附安装包)

Vivado 2019.2 作为 Xilinx 公司发布的一款设计套件版本,具有多个显著的优点,以下是对其优点的详细归纳

dpwkj的博客 1万+

TCP详解

详细介绍TCP的相关知识,如有错误或不足,欢迎指正!

长岛冰茶去冰的博客 1万+

智能车数字图像处理算法入门及C语言实现

智能车图像的最最基本入门算法介绍及C语言实现,二值化 - 特征识别 - 补线 - 中心巡线 - 偏差曲率计算。

不想随波逐流的大学生一枚,我们每个人都在努力奔跑 5110

传输层TCP协议

传输层TCP协议

Xpccccc的博客 906

hwasan实例分析踩内存之一:camx进程stack tag-mismatch的三种解决方案

hwasan实例分析踩内存之一:camx进程stack tag-mismatch的三种解决方案。

1291

基于YOLOv8的包装商品智能检测系统完整指南—含论文、代码

《基于YOLOv8的包装商品智能检测系统》摘要: 本文提出了一套完整的零售商品自动检测解决方案,利用YOLOv8深度学习框架实现高精度、高效率的商品识别。系统针对SKU110K大规模商品数据集(含11,762张高密度货架图像)进行优化,包含数据预处理、模型训练、推理检测和可视化界面全流程。详细介绍了从CSV标注到YOLO格式的转换方法、环境配置指南及技术架构设计。该系统可应用于智能零售、物流仓储等多个场景,有效解决人工盘点效率低、误差大的痛点。实验表明,该系统具备毫秒级检测速度和批量处理能力,为商业数字化转

FJN110的博客 209

传输层TCP协议和UDP协议

传输层协议

qq_44700820的博客 3902

深入解析ZYNQ PL触发PS中断:从原理到创新实践

通过本文,您不仅学会了ZYNQ PL-PS中断的基础实现,更掌握了动态优先级调整中断负载均衡等创新技术。响应延迟降低40%以上系统吞吐量提升2-3倍功耗降低30%支持更复杂的实时应用硬件是身体的骨骼,软件是流动的血液,而中断则是连接二者的神经系统。只有精确控制每一条神经冲动,才能构建真正智能的嵌入式系统。拓展思考如何将AI决策引入中断调度?能否实现跨芯片中断同步?量子计算对中断架构的挑战?

QQ_778132974的博客 417

传输层协议TCP

TCP协议核心机制解析 摘要:TCP(传输控制协议)是一种可靠的、面向连接的传输层协议。其核心机制包括:1)确认应答(ACK)机制确保数据可靠传输;2)超时重传解决丢包问题;3)连接管理通过三次握手建立连接、四次挥手断开连接;4)滑动窗口实现流量控制;5)拥塞控制预防网络拥堵。TCP还采用延迟应答、捎带应答等优化策略提高性能。相比UDP,TCP通过复杂的可靠性机制保障数据传输,但也存在粘包问题需应用层处理。文章详细解析了TCP协议段格式、状态转换及异常处理等核心内容,并对比了TCP/UDP的应用场景差异。

让每一行代码都有改变世界的力量。 871

NVIDIA Isaac Sim 入门教程(二)

Omniverse Isaac Sim 的工作空间非常容易自定义。调整用户界面的大小、停靠、取消停靠、添加和移除面板都非常容易。进入顶部菜单栏,单击下拉菜单最下方的窗口 > 视口 > 视口 2(现在工作区中应该会出现一个名为 "视口 2 "的新视口。如果您想创建更多的视口,请按照相机检查器扩展进行操作。单击并拖动视口 2 的顶部标题以激活停靠部件。拖放到原始视口的右侧,将两个视口并排放置。单击并向左拖动视口 2 的左侧,使视口大小相等。

机器人控制与仿真应用 6545

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

深入了解传输层协议TCP

传输层的作用是提供端到端的服务,即程序进程之间的通讯

qq_58522525的博客 1013

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

传输层协议:TCP 与 UDP

在计算机网络中,传输层位于网络层之上,应用层之下,主要负责提供端到端的可靠数据传输服务。传输层协议可以分为两大类:无连接的传输层协议和面向连接的传输层协议。

JAZJD的博客 1491

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

TCP和UDP传输层协议

TCP 是一种可靠的、面向连接的协议,适用于对数据传输可靠性要求高的场景,具有较高的延迟和开销,但能保证数据准确无误地传输。UDP 是一种无连接的、轻量级的协议,适用于实时性要求高、可以容忍丢包的场景,具有较低的延迟和开销,但不保证数据的可靠性、顺序和完整性。根据不同的应用需求,选择合适的协议可以有效提高网络通信的效率和用户体验。

qq_50847694的博客 1900

网络基础二——传输层协议UDP与TCP

传输层协议 UDP和TCP的认识

qq_33093885的博客 2427

传输层协议 ——— TCP协议

在进行网络通信时,一方发出的数据后,它不能保证该数据能够成功被对端收到,因为数据在传输过程中可能会出现各种各样的错误,只有当收到对端主机发来的响应消息后,该主机才能保证上一次发送的数据被对端可靠的收到了,这就叫做真正的可靠。但TCP要保证的是双方通信的可靠性,虽然此时主机A能够保证自己上一次发送的数据被主机B可靠的收到了,但主机B也需要保证自己发送给主机A的响应数据被主机A可靠的收到了。

weixin_53831496的博客 1440

【TCP/IP协议栈】4. 传输层协议(TCP、UDP)

协议森林07 傀儡 (UDP协议) - Vamei - 博客园TCP和UDP详解(非常详细)_tcp udp-优快云博客我们已经讲解了物理层、连接层和网络层。最开始的连接层协议种类繁多(Ethernet、Wifi、ARP等等)。到了网络层,我们只剩下一个IP协议(IPv4和IPv6是替代关系)。进入到传输层(transport layer),协议的种类又开始繁多起来(比如TCP、UDP、SCTP等)。

m0_74209072的博客 2590

传输层协议——TCP协议

例如图中的1001-2000的数据包如果在传输过程中丢包了,此时虽然2001-5000的数据都被对方收到了,此时对方发来的确认序号也只能是1001,当发送端补发了1001-2000的数据包后,对方发来的确认序号就会变为5001,此时发送缓冲区当中1001-5000的数据也会立马被归置到滑动窗口的左侧。TCP建立连接,数据通信,断开连接,一定会发送TCP报文,TCP发送的报文一定是各种类型的,不同的类型,决定了服务端要做不同的动作,接收方如何得知,报头的类型各自是什么呢?

m0_73634434的博客 1961

传输层的TCP和UDP协议

TCP和UDP都是传输层协议。TCP/IP是一个协议簇,里面包含了很多协议,UDP和TCP只是其中两个协议,之所以命为TCP/IP,是因为这两个协议非常重要。 1.TCP协议 TCP 的英文全拼(Transmission Control Protocol)简称传输控制协议,它是一种面向连接的、可靠的、,相对比较慢、点对点、基于字节流的传输层通信协议。TCP协议适用于对可靠性要求比较高的场合。比...

Healer_LU的博客 2062

传输层的重要协议——TCP

TCP协议的主要特点和原理

qq_54225038的博客 1182
上一篇: 传输层协议——UDP
下一篇: 网络层协议——IP
清源妙木真菌
博客等级 码龄3年 635粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值