面向连接的运输:TCP
传输控制协议(Transmission Control Protocol,TCP)
TCP 的特点#
- 全双工:建立连接的双方可以互相通信;
- 点对点:一个发送方只能对应一个接收方;
- 面向连接:发送正式数据之前必须先互相“握手”;
TCP 报文段结构#
与UDP相似,TCP报文段结构同样分为首部和数据。
TCP 首部字段#
首部字段包括:源端口号、目的端口号、检验和字段(checksum field)、序号字段(sequence number field)、确认号字段(acknowledgment number field)、接收窗口字段(receive window field)、首部长度字段(header length field)、选项字段(options field)、标志字段(flag field);
字段 | 长度/bit | 说明 |
---|---|---|
源端口号 | 16 | 发送端端口号 |
目的端口号 | 16 | 接收端端口号 |
检验和字段(checksum field) | 16 | 检验数据完整性 |
序号字段(sequence number field) | 32 | 实现可靠数据传输 |
确认号字段(acknowledgment number field) | 32 | 实现可靠数据传输 |
接收窗口字段(receive window field) | 16 | 流量控制 |
首部长度字段(header length field) | 4 | 首部长度 |
选项字段(options field) | 可选、变长 | 窗口调节因子 |
标志字段(flag field) | 6 | ACK、RST、SYN、FIN、PSH、URG |
紧急数据指针字段 | 16 | 紧急数据的最后一个字节 |
标志字段(flag field)#
- ACK:指示确认字段中的值是有效的,即该报文段包括一个对已被成功接收报文段的确认;
- RST|SYN|FIN: 用于连接的建立和拆除;
- PSH:指示接收方应立即将数据交给上层;
- URG:指示报文段里存在着被发送端的上层实体设置为“紧急”的数据;
TCP 数据字段#
数据字段包含一块应用数据 。MSS 限制了报文段数据字段的最大长度。
- 当 TCP 发送一个大文件,例如某 Web 页面上的一个图像时, TCP 通常是将该文件划分成长度为 MSS 的若干块(最后一块除外,它通常小于MSS);
- 交互式应用通常传送长度小于 MSS 的数据块,如 Telnet 的TCP报文段的数据字段经常只有一个字节;
可靠数据传输#
序号#
- TCP把数据看成一个无结构的、有序的字节流;
- 序号是建立在传送的字节流上,一个
报文段的序号
是该报文段首字节的字节流编号; - TCP隐式地对数据流中的每一个字节编号;
- TCP会根据
MSS
大小将数据流划分为多个报文段;
确认号#
累计确认
(cumulative acknowledgment): TCP 只确认数据流中至第一个丢失字节为止的字节;- 主机A填充进
报文段的确认号
是主机A期望从主机B收到的下一字节的序号; - 失序处理:接收方保留失序字节,并等待缺少的字节以填补该间隔;
往返时间估计与重传超时间隔#
往返时间估计#
在任意时刻,仅为一个已发送的但目前尚未被确认的报文段估计 SampleRTT ,从而产生一个接近每个 RTT 的新 SampleRTT 值。
TCP 决不为已被重传的报文段计算SampleRTT;它仅为传输一次的报文段测量 SampleRTT。
在已知EstimatedRTT
与DevRTT
后就可以确定超时间隔,计算公式如下: $TimeoutInterval=EstimatedRTT +4 * DevRTT$
重传超时间隔#
- 初始TimeoutInterval指为1秒,当出现超时后加倍,
- 每当定时器在另两个事件(即收到上层应用的数据和收到 ACK)中的任意一个启动时,Timeoutlnterval 由最近的 EstimatedRTT 值与 DevRTT 值推算得到。
快速重传#
- 冗余ACK(duplicate ACK): 再次确认某个报文段的ACK,而发送方先前已经收到对该报文的确认;
- 快速重传(fast retransmit): 一旦收到3个冗余ACK,TCP就在该报文段的定时器过期之前重传丢失的报文段;
当 TCP 接收方收到一个其序号大于下一个所期望的、按序的报文段,它检测到了数据流中的一个间隔,这就是说有报文段丢失。因为 TCP 不使用否定确认,所以接收方只是对已经接收的最后一个按序字节数据进行重复确认(产生一个冗余ACK)。
差错恢复#
TCP 的差错恢复机制可用看作为 GBN 协议与 SR 协议的混合体。
TCP 确认是累计式的,正确接收但失序的报文不会被接收方逐个确认;
因此,TCP 发送方仅需维持已发送过但未被确认的字节的最小序号(SendBase),和下一个要发送的字节的序号(NextSeqNum);
许多 TCP 实现会将正确接收但失序的报文段缓存起来;
- 选择确认(selective acknowledgment): 允许 TCP 接收方有选择地确认失序报文段,而不是累积地确认最后一个正确接收的有序报文段;
流量控制与拥塞控制#
- 流量控制服务(flow-control service): 一个速度匹配服务,控制发送方的发送速率与接收方应用程序的读取速率相匹配;
- 拥塞控制(congestion control): 发送方因IP网络的拥塞而被遏制;
- 接收窗口(receive window, rwnd): 由发送方维护,用于监控接收方还有多少可用的缓存空间;
流量控制#
当主机 B 的接收窗口为 $0$ 时,主机 A 继续发送只有一个字节数据的报文段。这些报文段将会被接收方确认。最终缓存将开始清空,并且确认报文里将包含 一个非 $0$ 的 rwnd
(缓存空间可用数量)值。
拥塞控制#
拥塞的代价#
- 当分组的到达这率接近链路容量时,分组经历巨大的排队时延。
- 发送方必须执行重传以补偿因为缓存溢出而丢弃(丢失)的分组。
- 发送方在遇到大时延时所进行的不必要重传会引起路由器利用其链路带宽来转发不必要的分组副本。
- 当一个分组沿一条路径被丢弃时,每个上游路由器用于转发该分组到丢弃该分组而使用的传输容量最终被浪费掉了 。
拥塞控制方法#
- 端到端拥塞控制:端系统必须通过对网络行为的观察(如分组丢失与时延)来推断;
- 网络复制的拥塞控制:网络层构件(即路由器)向发送方提供关于网络中拥塞状态的显式反馈信息。
TCP 拥塞控制#
1、发送方限制向其连接发送流量的速率#
拥塞窗口(congestion window, cwnd):运行在发送方的TCP拥塞控制机制跟踪一个额外的变量,实现对TCP发送方能向网络中发送流量的速率进行限制;
- 在一个发送方中未被确认的数据量不会超过 cwnd 与 rwnd 中的最小值;
- 该发送方的发送速率大概是 $cwnd/RTT$ 字节/秒。通过调节 cwnd 的值,发送方因此能调整它向连接发送数据的速率。
2、发送方感知从它到目的地之间的路径上存在拥塞#
"丢包事件":要么出现超时,要么接收到来自接收方的3个冗余ACK;
当出现过度的拥塞时,在沿着这条路径上的一台(或多台)路由器的缓存会溢出,引起一个数据报(包含一个 TCP 报文段)被丢弃。丢弃的数据报接着会引起发送方的丢包事件(要么超时或收到 3 个冗余 ACK) ,发送方就认为在发送方到接收方的路径上出现了拥塞的指示。
3、当发送端感知到端到端的拥塞时,为改变其发送速率采用的算法#
- 一个丢失的报文段表意味着拥塞,因此当丢失报文段时应当降低 TCP 发送方的速率。
- 一个确认报文段指示该网络正在向接收方交付发送方的报文段,因此,当对先前未确认报文段的确认到达时,能够增加发送方的速率。
- 带宽探测。
TCP 拥塞控制算法(TCP congestion control algotithm): 慢启动、拥塞避免、快速恢复;TCP 拥塞控制常常被称为加性增、乘性减(Additive-lncrease, Multiplicative-Decrease, AIMD)拥塞控制方式。
连接管理#
建立连接#
三次握手(three-way handshake)
- 第一步:客户端的 TCP 首先向服务器端的 TCP 发送一个特殊的 TCP 报文段(SYN 报文段);SYN=1;
- 第二步:SYN报文段到达服务器端,服务器会为该TCP连接分配TCP缓存和变量,并向客户端发送允许连接的报文段(SYNACK 报文段);SNY=1;
- 第三步:客户端收到SYNACK报文段,客户端也要为该连接分配缓存和变量,并向服务器端发送另外一个报文(对SYNACK报文端的确认);SNY=0;
关闭连接#
参与一条 TCP 连接的两个进程中的任何一个都能终止该连接。
以客户准备关闭连接为例:
- 客户端向服务端发送一个特殊的TCP报文段--终止报文段(FIN=1);
- 服务器收到后向发送方(客户端)回送一个确认报文段(ACK),然后服务端发送自己的终止报文段(FIN-1);
- 最后,客户端对服务端的终止报文段进行确认,经过定时等待时间后连接正式关闭;
SYN洪泛攻击(SYN flood attack)#
攻击者发送大量TCP SYN报文段,而不完成第三次握手的步骤,服务器不断为这些半开连接分配资源,导致服务器的连接资源被消耗殆尽。
SYN cookie#
- 服务器接收到一个SYN 报文段时,并不立刻分配资源,而是生成一个cookie作为初始序列号放入SYNACK报文段发送给客户端;服务器并不记忆该 cookie 或任何对应于 SYN的其他状态信息。
- 在合法客户端的ACK报文段中 $确认字段中的值=SYNACK字段中的值(cookie值) + 1$,服务端则根据报文段中数据以相同规则生成一个cookie值,若 $cookie值 + 1 = 确认字段值$,说明该ACK对应较早的SYN报文段,因此是合法的,服务器则生成一个具有套接字的全开的连接;
作者:issenxiao
出处:https://www.cnblogs.com/issenxiao/articles/18273517
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】