TCP协议理解
文章目录
- TCP协议理解
- 理论基础
- TCP首部
- 结构图示
- 字段逐项解析
- TCP是面向连接(Connection-Oriented)
- 面向连接的核心表现
- TCP 面向连接的核心特性
- TCP 与UDP对比
- TCP是一个可靠的(reliable)
- 序号与确认机制(Sequencing & Acknowledgment)
- 正常数据传输过程图示
- 连接建立(三次握手)
- 数据传输
- 连接释放(四次挥手)
- 补充说明
- 超时重传(Retransmission Timeout, RTO)
- 正常传输(无重传)
- 数据包丢失(F1 丢失)
- ACK 丢失(ACK1 丢失)
- ACK 延迟(ACK1 延迟)
- 数据包与 ACK 均丢失(F1 + ACK1 丢失)
- 接收方处理慢(ACK1 延迟)
- 流量控制(Flow Control)
- TCP 流量控制的工作原理
- 流量控制的实现方式
- 关键字段与术语
- 举个例子来说明:
- 拥塞控制(Congestion Control)
- 拥塞控制的原理
- 拥塞控制的五种机制
- 拥塞控制的工作过程
- 拥塞控制算法的实际过程
- 拥塞控制的主要参数
- 拥塞控制算法示例:TCP Reno 和 TCP Tahoe
- 活动窗口+丢包重传机制图示
- 滑动窗口(Sliding Window)
- 丢包重传机制
- 动态序列号与确认号
- 连接释放
- 模拟丢包测试
- TCP是基于字节流(byte-TCPstream)的理解
- 五种典型场景说明:
- 关键结论:
- 全双工的协议特性
- 补充知识
- 端口号
- 作用
- 端口号范围
- TCP 常用端口
- Socket、五元组与TCP/IP协议的关系
- Socket(套字节) 是网络编程的基石
- 五元组是连接的唯一标识
- 分层图示:TCP/IP协议栈与Socket的位置
- TCP连接建立的五元组交互(三次握手)
TCP协议理解
TCP是一个可靠的(reliable) 、面向连接的(connection-oriented)、基于字节流(byte-TCPstream)、全双工的(ful1-duplex) 协议。可靠传输是通过一系列复杂的机制实现的,确保数据在网络中有序、无丢失、无重复地到达目标端。
理论基础
TCP首部
结构图示
字段逐项解析
- 源端口 & 目的端口(各16位)
- 作用:标识发送方和接收方的应用程序。
- 源端口:客户端随机分配(动态端口,范围49152~65535)。
- 目的端口:服务端固定端口(如HTTP:80、SSH:22)。
- 作用:标识发送方和接收方的应用程序。
- 序列号(32位)
- 作用:标识发送的数据字节流的顺序号,解决乱序问题。
- 初始序列号(ISN):在三次握手时随机生成,避免历史报文冲突。
- 规则:每发送1字节数据,序列号+1。
- 作用:标识发送的数据字节流的顺序号,解决乱序问题。
- 确认号(32位)
- 作用:期望收到的下一个字节的序列号,实现可靠传输。
- 规则:确认号 = 对方序列号 + 已接收数据长度 + 1(若含SYN/FIN标志,+1)。
- 数据偏移(4位)
- 作用:指示TCP头部长度(以4字节为单位)。
- 计算:头部长度 = 数据偏移值 × 4(最小5,即20字节;最大15,即60字节)。
- 作用:指示TCP头部长度(以4字节为单位)。
- 保留字段(6位)
- 作用:保留给未来使用,必须置0。
- 控制标志(6位,每1位表示一个状态)
标志位 | 名称 | 作用 |
---|---|---|
URG | 紧急 | 为1时,启用紧急指针(需配合紧急指针字段) |
ACK | 确认 | 为1时,确认号有效(建立连接后所有报文ACK=1) |
PSH | 推送 | 为1时,要求接收方立即将数据交给应用层(如Telnet输入) |
RST | 重置 | 为1时,强制断开连接(用于异常恢复) |
SYN | 同步 | 为1时,表示发起连接请求(三次握手阶段使用) |
FIN | 结束 | 为1时,表示发送方数据发送完毕(四次挥手阶段使用) |
-
常见组合:
- SYN=1, ACK=0:第一次握手(连接请求)
- SYN=1, ACK=1:第二次握手(连接确认)
- SYN=0, ACK=1:第三次握手 (建立连接)
- 传输数据。。。。
- FIN=1, ACK=1:四次挥手 (关闭连接请求)
-
窗口大小(16位)
- 作用:接收方的可用缓冲区大小(流量控制关键字段)。
- 单位:字节(最大65535字节,若启用窗口缩放选项可扩展)。
- 动态调整:通过滑动窗口协议控制发送速率。
- 作用:接收方的可用缓冲区大小(流量控制关键字段)。
-
校验和(16位)
- 作用:检测头部和数据的传输错误(覆盖伪头部+TCP头部+数据)。
- 算法:反码求和再取反。
- 伪头部字段:包含源/目的IP、协议类型等,增强校验强度。
- 作用:检测头部和数据的传输错误(覆盖伪头部+TCP头部+数据)。
-
紧急指针(16位)
- 作用:当URG=1时,指示紧急数据的末尾偏移量(相对于序列号)。
- 应用场景:中断远程命令(如Ctrl+C)。
-
选项字段(可选)
- 作用:扩展TCP功能,常见选项:
类型 长度 功能 MSS(最大报文段) 4字节 协商双方能接收的最大数据段长度 窗口缩放 3字节 将窗口大小扩展至1GB(左移0~14位) SACK(选择性确认) 可变 支持只重传丢失的报文段 时间戳 10字节 计算RTT(往返时间)和防止序号回绕
TCP是面向连接(Connection-Oriented)
面向连接的核心表现
-
三次握手(建立连接)
-
SYN:A 发起连接请求,携带初始序列号(seq=100)。
-
SYN-ACK:B 确认 A 的序列号(ack=101),并发送自己的序列号(seq=300)。
-
ACK:A 确认 B 的序列号(ack=301),连接建立。
-
-
数据传输(可靠传输)
-
PSH:A 发送数据 “hello”(占 5 字节,seq=101),B 必须回复 ACK(ack=106)。
-
应用层响应:B 发送 “world”(可选,由应用协议决定)。
-
-
四次挥手(释放连接)
-
FIN:A 发起关闭请求。
-
ACK:B 确认收到,可能继续发送剩余数据。
-
FIN:B 发起关闭请求。
-
ACK:A 确认,连接完全关闭。
-
TCP 面向连接的核心特性
特性 | 说明 | 图示对应部分 |
---|---|---|
预先建立连接 | 通信前需通过三次握手协商参数(序列号、窗口大小等)。 | 三次握手阶段 |
可靠传输 | 每个数据包必须被确认(ACK),超时重传,保证数据不丢失、不重复、按序到达。 | 数据传输阶段的 ACK 机制 |
状态维护 | 两端维护连接状态(如 ESTABLISHED、TIME_WAIT)。 | 整个生命周期 |
有序释放连接 | 通过四次挥手安全关闭连接,避免数据丢失。 | 四次挥手阶段 |
TCP 与UDP对比
对比项 | TCP | UDP |
---|---|---|
全称 | 传输控制协议(Transmission Control Protocol) | 用户数据报协议(User Datagram Protocol) |
连接性 | 面向连接(需三次握手建立连接) | 无连接(直接发送数据) |
可靠性 | 可靠传输(确认、重传、排序机制) | 不可靠传输(无确认、重传机制) |
数据顺序 | 保证数据按序到达 | 不保证数据顺序 |
流量控制 | 支持(滑动窗口机制) | 不支持 |
拥塞控制 | 支持(动态调整发送速率) | 不支持 |
传输速度 | 较慢(需额外控制机制) | 较快(无额外控制开销) |
头部大小 | 较大(20-60 字节,包含更多控制信息) | 较小(8 字节,固定头部) |
适用场景 | 对可靠性要求高的场景(如网页、文件传输) | 对实时性要求高的场景(如视频流、在线游戏) |
数据边界 | 无明确边界(基于字节流) | 有明确边界(保留数据报边界) |
协议复杂度 | 复杂 | 简单 |
典型应用 | HTTP、FTP、SMTP、SSH | DNS、VoIP、直播、在线游戏 |
UDP数据传输图示
TCP是一个可靠的(reliable)
TCP 通过以下 4 种关键技术保证可靠性:
序号与确认机制(Sequencing & Acknowledgment)
正常数据传输过程图示
注意:上图中大写的ACK是标志位,小写ack是回应对方的确认号
-
用netcat 和 wireshare 模拟抓包TCP过程
连接建立(三次握手)
- SYN: 同步序列号,初始化连接。
- ACK: 确认对方的序列号。
- 最终双方进入 ESTABLISHED 状态。
- 三次握手示意图
数据传输
- 每次发送数据时:
- seq 为当前数据包的起始序列号。
- ack 为期望收到的下一个字节的序列号(即对方seq + 数据长度)。
- 示例中传输了三条数据:“Hello” → “Hi” → “Bye”。
连接释放(四次挥手)
- FIN: 终止连接请求。
- 客户端和服务器各自发送 FIN 并确认对方的 FIN,最终进入 CLOSED 状态。
- 客户端在 TIME_WAIT 状态等待 2MSL(确保最后一个 ACK 到达服务器)。
- 状态说明表格:
状态 | 所属方 | 含义 |
---|---|---|
FIN-WAIT-1 | 客户端 | 发送FIN后等待服务器ACK确认 |
CLOSE-WAIT | 服务器 | 收到FIN后进入半关闭状态,等待应用层处理剩余数据 |
FIN-WAIT-2 | 客户端 | 收到服务器ACK后,等待服务器发送FIN |
LAST-ACK | 服务器 | 发送FIN后等待客户端最终ACK确认 |
TIME-WAIT | 客户端 | 发送最后一个ACK后等待2MSL(防止ACK丢失,确保服务器能正常关闭) |
CLOSED | 双方 | 连接完全关闭 |
-
什么是
MSL
?
MSL(Maximum Segment Lifetime,报文最大生存时间)是 TCP 报文在网络中的最长存活时间,超过该时间未被接收的报文会被丢弃。2MSL 是 TCP 连接在 TIME-WAIT 状态的等待时长,即 两倍的 MSL。- 在 Linux 系统中,MSL 默认为 60秒,因此 TIME-WAIT 状态持续 120秒(2MSL)。
- Windows 系统中 MSL 通常为 2分钟(TIME-WAIT 为 4分钟)。
-
为什么需要
TIME-WAIT
?-
确保最后一个ACK到达服务器,若丢失,服务器会重传FIN,客户端可重新响应ACK。
-
防止旧连接的延迟数据包干扰新连接(通过2MSL等待旧数据包失效)。
-
wireshare抓包情况
-
在windows下cmd中用
netstat
工具查看连接状态
-
补充说明
-
序列号(seq)和确认号(ack)
- 每次传输数据后,seq 和 ack 会动态变化,遵循规则:
- ack = 对方上一次的seq + 数据长度。
-
为什么需要三次握手四次挥手?
-
三次握手的原因
-
确认双向通信能力
通过客户端发送SYN、服务端回复SYN+ACK、客户端再回复ACK的三次交互,验证双方的发送和接收功能正常。 -
同步初始序列号
交换序列号(seq)和确认号(ack),为后续数据传输提供有序性保障。 -
防止历史连接干扰
若网络延迟导致旧SYN报文到达,服务端会要求客户端确认,避免无效连接占用资源。 -
协商窗口参数
在握手过程中同步TCP窗口大小等配置,优化数据传输效率。
-
-
四次挥手的原因
-
全双工连接的独立关闭
TCP连接是双向的,客户端和服务端需分别发送FIN和ACK来关闭各自的通道。- 第一次挥手:主动方发送FIN,表示不再发送数据。
- 第二次挥手:被动方回复ACK,确认收到关闭请求。
- 第三次挥手:被动方发送FIN,表示自身数据已发送完毕。
- 第四次挥手:主动方回复ACK,最终确认连接释放。
-
确保数据完整性
四次挥手允许被动方在ACK后继续发送剩余数据,避免数据丢失。 -
处理延迟报文
通过TIME_WAIT状态等待可能滞留在网络中的报文,防止新连接收到旧数据。
-
-
为什么不简化握手或挥手?
-
两次握手不足
无法验证客户端的接收能力,且易受历史SYN报文干扰。 -
三次挥手不可行
被动方的ACK和FIN通常无法合并发送,因为数据可能未传输完成。
-
通过这种设计,TCP在不可靠的IP层上实现了可靠的端到端通信。
-
-
理解Wireshare抓包中的序列号(seq)和确认号(ack)都是wireshare处理后的相对序号/确认号
-
实际传输值
-
是32位无符号整数,范围0-4294967295
-
表示该报文段中第一个数据字节的编号
-
初始序列号(ISN)是随机生成的(安全考虑)
-
-
Wireshark显示方式
-
相对序号:默认显示相对于初始序列号的偏移量
-
第一个包的Seq显示为0(实际可能是任意ISN值)
-
后续包显示相对于ISN的增量
-
绝对序号:可通过右键菜单切换显示实际值
-
-
超时重传(Retransmission Timeout, RTO)
TCP 超时重传场景分析
正常传输(无重传)
-
流程:
F1 (Seq=1) → ACK1 → F2 (Seq=2)
-
说明:
数据包和 ACK 均正常到达,无需重传。
数据包丢失(F1 丢失)
-
流程:
F1 (丢失) → [超时] → F1 (重传) → ACK1
-
原因:
网络拥塞、链路错误导致数据包丢失。 -
解决方案:
- 启用 快速重传(Fast Retransmit)(需 SACK 支持)
- 优化网络路径(如切换路由、检查 QoS)
ACK 丢失(ACK1 丢失)
-
流程:
F1 (Seq=1) → ACK1 (丢失) → [超时] → F1 (重传) → ACK1 (重发)
-
原因:
接收方的 ACK 确认包丢失,发送方误判数据未到达。 -
解决方案:
- 动态调整 RTO(重传超时时间) 减少误判
- 使用 SACK(选择性确认) 避免重复传输已接收数据
ACK 延迟(ACK1 延迟)
-
流程:
F1 (Seq=1) → ACK1 (延迟) → [超时] → F1 (重传) → ACK1 (重发)
-
原因:
ACK 因网络抖动延迟到达,触发不必要的重传。 -
解决方案:
- 优化 RTT(往返时间) 计算算法(如 Linux 默认的 RFC6298)
- 启用 时间戳选项(TCP Timestamps) 更精确估算延迟
数据包与 ACK 均丢失(F1 + ACK1 丢失)
-
流程:
F1 (丢失) + ACK1 (丢失) → [超时] → F1 (重传) → ACK1
-
原因:
双向通信均失败,可能是网络分区或严重拥塞。 -
解决方案:
- 增加 最大重传次数(如 Linux 的 tcp_retries2)
- 监控网络状态(如 ICMP 探测、BGP 路由检查)
接收方处理慢(ACK1 延迟)
-
流程:
F1 (Seq=1) → [处理延迟] → [超时] → F1 (重传) → ACK1 (重发)
-
原因:
接收方应用层处理缓慢(如缓冲区满、高负载)。 -
解决方案:
- 调整接收方 TCP 接收窗口(RWND)
- 优化应用代码(如异步 I/O、批量处理)
流量控制(Flow Control)
TCP 流量控制是确保在网络通信中发送方不会过度传输数据以至于接收方无法及时处理的机制。流量控制的核心目的是防止接收方的缓冲区溢出,确保数据传输的可靠性和稳定性。
TCP 流量控制的工作原理
在 TCP 连接中,流量控制依赖于 接收窗口(Receive Window) 来管理数据传输。接收窗口是接收方通知发送方当前可用的缓冲区空间大小,发送方根据这个窗口来决定可以发送多少数据。
以下是 TCP 流量控制的主要概念:
-
接收窗口(Window Size):
- 每次发送方发送数据时,它会检查接收方的接收窗口大小。接收窗口大小由接收方在每个 TCP 数据包的头部通知给发送方。
- 接收窗口的大小决定了在不等待确认的情况下,发送方最多可以发送的字节数。接收方通过不断地更新窗口大小来通知发送方当前可接受的缓冲区空间。
-
滑动窗口(Sliding Window):
- TCP 使用滑动窗口机制来进行流量控制,发送方通过滑动窗口来控制数据的流量。
- 当接收方确认已收到数据时,窗口向前滑动,释放出空间,从而允许发送方发送更多的数据。
- 这个窗口并不是固定大小的,它会随着接收方处理数据的速度和窗口大小的更新而动态调整。
-
流量控制过程:
- 发送方:发送方发送数据到接收方,并在每个数据包中包含当前的接收窗口大小。
- 接收方:接收方在收到数据后,会根据其缓冲区的空闲空间更新接收窗口大小。
- 滑动窗口更新:当接收方成功处理某些数据并释放缓冲区空间时,接收方会通过窗口更新通知发送方,发送方则可以继续发送数据。
流量控制的实现方式
- 接收方窗口大小的动态调整:
- 在 TCP 握手期间,接收方会告知发送方自己的接收窗口的大小。
- 接收方根据自己的缓冲区的使用情况来调整接收窗口。如果接收方的缓冲区已经满了,接收窗口会变小或甚至为零,这会告诉发送方暂时停止发送数据。
- 例如,当接收方的缓冲区空间快用完时,接收窗口会减少,发送方的发送速率也会受到影响。
- 流量控制与拥塞控制:
- 流量控制与拥塞控制是 TCP 中的两个不同机制。流量控制关注的是如何控制数据传输速率以避免接收方缓冲区溢出,而拥塞控制则是为了避免网络中的过度拥塞。
- 流量控制是基于接收方的缓冲区情况来进行调节,而拥塞控制则是基于整个网络的负载情况进行调节。
关键字段与术语
-
rwnd (Receive Window):
- rwnd 是接收窗口的大小,表示接收方的缓冲区剩余的可用空间。这个值会通过 TCP 头部的字段传递给发送方。
-
窗口大小字段:
- 在 TCP 头部,有一个字段专门用于表示接收窗口大小,它是一个 16 位的数值,表示当前接收方能接收的字节数。
举个例子来说明:
假设发送方正在发送大量的数据,而接收方的接收窗口初始大小为 10,000 字节。发送方会按照这个窗口大小发送数据。
- 发送方发送了 10,000 字节的数据。
- 接收方处理了其中的一部分数据并释放了 4,000 字节的缓冲区空间。
- 接收方通过更新窗口大小,告知发送方新的接收窗口大小为 4,000 字节。
- 发送方在接收到这个更新的窗口大小后,调整自己的发送速率,并根据接收窗口的大小来决定可以发送多少数据。
- 如果接收方的缓冲区空间已满,接收窗口大小会变为零,通知发送方停止发送数据,直到接收方处理了足够的数据,窗口大小才会重新增大。
拥塞控制(Congestion Control)
拥塞控制(Congestion Control)是 TCP 协议中一个非常重要的机制,旨在防止网络中的数据包过度积压或拥堵,从而影响数据的传输效率与可靠性。它的主要目标是确保数据传输在网络的可承载范围内进行,避免因网络负载过高导致的丢包、延迟和流量不稳定。
拥塞控制的原理
拥塞控制的核心思想是根据网络的实际状况(如带宽、延迟、丢包率等)动态调整发送方的数据发送速率,以防止网络拥塞。当网络出现拥塞时,TCP 会自动减慢数据发送速率;当网络空闲时,TCP 会逐步增加发送速率。
拥塞控制的五种机制
- 慢启动(Slow Start)
- 拥塞避免(Congestion Avoidance)
- 快速重传(Fast Retransmit)
- 快速恢复(Fast Recovery)
- 拥塞窗口(Congestion Window, cwnd)
拥塞控制的工作过程
-
慢启动阶段(Slow Start):
- 初始时,TCP 连接的拥塞窗口(cwnd)被设置为一个小的值(通常为 1 或 2 个最大报文段长度(MSS))。
- 每收到一个确认(ACK)包,发送方就会将拥塞窗口大小增加一个 MSS,即窗口大小以指数级增长。
- 该阶段持续到拥塞窗口大小达到一个阈值(慢启动阈值,ssthresh),此时转入拥塞避免阶段。
-
拥塞避免阶段(Congestion Avoidance):
- 当拥塞窗口达到慢启动阈值后,TCP 会进入拥塞避免阶段。在这个阶段,窗口大小的增长速度会减缓,从指数增长转为线性增长。
- 每收到一个确认包,拥塞窗口(cwnd)会增加一个 MSS 除以当前的拥塞窗口大小。
- 这一阶段的目标是平稳地增加发送速率,避免因为过快的速率增加而导致网络拥塞。
-
丢包检测与快速重传(Fast Retransmit):
- 如果发送方连续收到三个相同的确认号(即出现三次重复确认),说明某个数据包丢失了。
- TCP 会立即重传丢失的数据包,而不需要等待超时。
- 快速重传的机制能够减少丢包后等待超时的时间,加速数据的恢复过程。
-
快速恢复阶段(Fast Recovery):
- 在丢包发生并进行快速重传后,TCP 会进入快速恢复阶段。在该阶段,拥塞窗口会进行适当的调整,通常是将拥塞窗口减半(cwnd = cwnd / 2),而不是直接回到慢启动阶段。
- 快速恢复阶段的目的是尽量恢复丢包后的网络状况,并避免过度回退。
-
拥塞窗口的调整:
- 在慢启动和拥塞避免阶段,TCP 会根据网络的反馈动态调整拥塞窗口大小。
- 当发生拥塞时(如丢包发生),TCP 会减小拥塞窗口的大小,并且通过逐步增加(慢启动)或线性增加(拥塞避免)来找到适合的发送速率。
拥塞控制算法的实际过程
-
慢启动:
- 初始时,cwnd 通常设为 1 MSS。
- 每当收到一个确认包(ACK),cwnd 就加 1 MSS,窗口大小呈指数增长。
- 当 cwnd 达到慢启动阈值(ssthresh)时,进入拥塞避免阶段。
-
拥塞避免:
- cwnd 达到 ssthresh 后,进入线性增长阶段。每收到一个确认包,cwnd 增加 1 MSS / cwnd。
- 这种增长是线性的,能够平稳地增加发送速率,防止网络过载。
-
快速重传与快速恢复:
- 在接收到 3 次重复确认时,认为发生了丢包。
- 快速重传会立即重发丢失的包,而不是等待超时。
- 快速恢复会将 cwnd 减少一半,然后继续进行拥塞避免。
拥塞控制的主要参数
-
拥塞窗口(Congestion Window,cwnd):
- 拥塞窗口是发送方控制发送速率的关键参数,它定义了在网络中可以未确认的数据的最大字节数。
- 拥塞窗口的大小会根据网络的拥塞状况动态调整。较大的 cwnd 可以提高数据传输速率,较小的 cwnd 会减少发送速率,从而缓解拥塞。
-
慢启动阈值(Slow Start Threshold,ssthresh):
- ssthresh 是决定 TCP 何时从慢启动阶段转到拥塞避免阶段的阈值。
- 当发生拥塞(如丢包)时,ssthresh 会减小,以限制数据的快速增长。
-
超时重传:
- 当发送方未收到某个数据包的确认(ACK)时,它会触发超时重传机制。这通常会导致拥塞窗口被重置为一个较小的值,并重新开始慢启动。
拥塞控制算法示例:TCP Reno 和 TCP Tahoe
- TCP Tahoe:使用慢启动、拥塞避免和超时重传机制。在发生丢包时,cwnd 会被重置为 1 MSS,然后重新进入慢启动阶段。
- TCP Reno:在 TCP Tahoe 的基础上增加了快速重传和快速恢复机制。当检测到丢包时,cwnd 会减小一半,并进入快速恢复阶段,而不是回到慢启动。
活动窗口+丢包重传机制图示
滑动窗口(Sliding Window)
- 窗口大小 Win=3 表示客户端无需等待ACK即可连续发送3个数据包(P1、P2、P3)。
- 服务器通过 ack 动态调整窗口(示例中因丢包暂停滑动)。
丢包重传机制
- 快速重传:服务器连续3次返回相同的 ack=2(表示P2丢失),客户端立即重传P2。
- 超时重传:P4未收到ACK,客户端等待超时后重传。
动态序列号与确认号
- 数据包长度影响 ack 值(如 data=“P1” 长度为1,则下一个 ack=2)。
- 重传包的 seq 不变(如P2重传时仍为 seq=2)。
连接释放
- 客户端和服务器各自发送 FIN 并确认,最终客户端进入 TIME_WAIT 状态(等待2MSL)。
模拟丢包测试
- 为了更精确地模拟滑动窗口和重传机制,使用
iperf
和netem
等工具制造条件- netem 是Linux内核中的一个网络模拟模块,它允许你模拟网络延迟、丢包、重复和乱序等条件,使用
tc
(Traffic Control)工具来配置 netem iperf
是一个网络性能测试工具(需要额外安装yum install -y iperf
),它可以用来测量TCP和UDP带宽性能。可以使用iperf
来模拟不同的带宽和延迟条件,从而观察TCP连接在这些条件下的行为
- netem 是Linux内核中的一个网络模拟模块,它允许你模拟网络延迟、丢包、重复和乱序等条件,使用
- 服务器端 使用
netem(tc)
模拟网络延迟和丢包
# 在服务端上设置50%丢包率
tc qdisc add dev eth0 root netem loss 50%# 启动iperf服务器
iperf -s
- 在另一台机器上运行客户端测试
# 设置非常小的窗口大小
iperf -c <server_ip> -w 1k
- 测试完成后移除服务端丢包规则
tc qdisc del dev eth0 root
TCP是基于字节流(byte-TCPstream)的理解
一种字节流协议,流的含义是没有固定的报文边界
五种典型场景说明:
-
完整发送
-
发送方三次写入(200B+300B+500B)→ 接收方一次读取1000B
-
典型场景:Nagle算法关闭时的小数据快速发送
-
-
拆分发送
-
原始数据被拆分为400B+600B两个TCP段
-
原因:MTU限制或拥塞控制导致分片
-
-
部分粘包
-
前两次写入(200B+300B)合并发送,第三次单独发送
-
接收方读取时出现500B+500B的分界
-
-
数据混合
-
当前应用数据与其他应用数据混合传输
-
需要应用层协议自行区分(如HTTP头部的Content-Length)
-
-
拆分成小包
-
大数据块被拆分为多个小包传输
-
常见于慢启动阶段或高延迟网络
-
关键结论:
-
TCP的字节流特性导致以下不确定性:
-
写入/读取次数不对应
-
数据块大小不对应
-
报文边界不保留
-
-
必须通过应用层协议解决:
-
最常用方案:长度前缀(如HTTP/WebSocket)
-
简单方案:分隔符(如Redis协议)
-
特殊场景:定长(如视频流分片)
-
全双工的协议特性
补充知识
端口号
端口号是网络通信中用于区分不同应用程序或服务的逻辑标识,与IP地址结合形成套接字(Socket),实现端到端的精准通信。
作用
-
定位应用层服务:同一台主机上可能有多个网络应用(如Web服务器、FTP服务器),端口号帮助区分这些服务。
-
多路复用/解复用:通过端口号,传输层(TCP/UDP)将数据准确交付给目标应用程序。
端口号范围
-
16位无符号整数:范围 0~65535(2^16)
-
分类
类型 | 范围 | 说明 |
---|---|---|
知名端口 | 0~1023 | 分配给系统服务(如HTTP:80) |
注册端口 | 1024~49151 | 用户程序可注册的端口(如MySQL:3306) |
动态/私有端口 | 49152~65535 | 客户端临时使用的端口(操作系统随机分配) |
TCP 常用端口
端口号 | 协议/服务 | 说明 |
---|---|---|
20/21 | FTP | 文件传输(数据/控制连接) |
22 | SSH | 安全远程登录 |
80 | HTTP | 网页访问 |
443 | HTTPS | 加密网页访问 |
3306 | MySQL | 数据库服务 |
3389 | RDP | 远程桌面协议 |
Socket、五元组与TCP/IP协议的关系
Socket(套字节) 是网络编程的基石
- 作用:Socket 是操作系统提供给应用程序的 编程接口(API),开发者通过它实现网络通信(如建立连接、发送数据)
- Socket 由以下几个部分组成:
- 协议族(如:IPv4 或 IPv6)
- 传输协议(如:TCP 或 UDP)
- 端口号
- IP 地址
在编程中,Socket 通常是通过操作系统提供的 API 来创建的,用于实现网络连接。Socket 使得应用程序可以通过指定端口、IP 地址和协议类型来进行通信。它是实现网络通信的抽象。
五元组是连接的唯一标识
组成:协议 + 源IP + 源端口 + 目标IP + 目标端口。
元素 | 说明 | 示例 |
---|---|---|
传输层协议 | 指明使用 TCP 还是 UDP | TCP、UDP |
源IP地址 | 发起通信的主机 IP 地址 | 192.168.1.100 |
源端口 | 发起通信的应用程序端口(临时端口,通常由操作系统动态分配) | 54322 |
目的IP地址 | 目标主机的 IP 地址 | 10.0.0.5 |
目的端口 | 目标应用程序的端口(知名端口或注册端口,如 HTTP-80、SSH-22) | 80 |
举例说明:
- 操作系统通过五元组区分不同的网络连接。例如,同一台主机上的多个浏览器标签访问同一网站时,每个连接的五元组中的 源端口 不同。
连接1: [TCP, 192.168.1.100:54322 → 10.0.0.5:80]
连接2: [TCP, 192.168.1.100:54323 → 10.0.0.5:80]
分层图示:TCP/IP协议栈与Socket的位置
+-----------------------+
| Application | ← 应用程序(HTTP/FTP/SSH)
+-----------------------+
| Socket | ← 编程接口(API)
+-----------------------+
| Transport (TCP/UDP) | ← 五元组在此层生效
+-----------------------+
| Network (IP/ICMP) |
+-----------------------+
| Link (Ethernet) |
+-----------------------+
- Socket 是应用层与传输层之间的桥梁,开发者通过它调用TCP/UDP功能。
- 五元组 在传输层(TCP/UDP)中唯一标识一个连接。
TCP连接建立的五元组交互(三次握手)
- 握手过程中,双方Socket根据五元组确认连接归属。