【计算基础|网络12】TCP 抓包与经典边界问题

【计算基础|网络12】TCP 抓包与经典边界问题

面试问你"三次握手",你能背;线上一个接口偶发超时、CLOSE_WAIT 堆积、连接池打满,你抓过包吗?这篇是工程实战篇------不讲教科书上的箭头图,直接上 tcpdump、Python socket、netstat,把五次真实事故复现给你看:怎么抓握手挥手、怎么复现重传、怎么把 TIME_WAIT 堆出来、拔网线时连接到底怎么死、以及 Keepalive 和 Keep-Alive 为什么是两回事。

环境:macOS 27、Python 3.14、tcpdump 4.99.1(macOS 自带)、netstat/lsof。⚠️ macOS 上抓包必须用 sudo(BPF 设备权限),下面命令请在你自己的终端里用 sudo 跑;本机非 root 环境用 lsof/netstat/socket 自省替代观察状态。


一、tcpdump 入门:十个参数记住就够

结论先给:tcpdump 不是用来"看所有包"的,是用来"按条件筛包"的。过滤表达式写错,要么什么都抓不到,要么包多到刷屏。

1.1 高频参数表

参数 作用 例子
-i any 抓所有网卡 tcpdump -i any
-i lo0 只抓回环(本地调试最常用) tcpdump -i lo0
-nn 不解析域名和端口名,直接显示 IP:端口 必加,慢死的元凶就是反查
-X 同时打印十六进制和 ASCII 看报文内容用
-vv 详细输出(更多字段) 排查时加
-c N 抓够 N 个包就退出 写脚本必加
-w file.pcap 原始包存文件,事后用 Wireshark 打开 留档取证
-r file.pcap 读 pcap 文件 离线分析
-s 0 抓完整包(默认 snaplen 96 字节,包会被截断) 抓完整头部必加

1.2 过滤表达式语法

过滤表达式是 tcpdump 的灵魂,记住下面这几个原词就够:

原词 含义 例子
host X 主机 X host 127.0.0.1
port N 端口 N port 8080
net 10.0.0.0/8 网段 net 10.0.0.0
src X 源地址是 X src 10.0.0.1
dst X 目的地址是 X dst 10.0.0.1
and / or / not 逻辑组合 port 8080 and not src 10.0.0.1
tcp[tcpflags] & tcp-syn != 0 SYN 包 抓握手用

1.3 三条能直接抄的命令

bash 复制代码
# ① 抓本机 8080 端口的所有包,不解析,抓 20 个就停
sudo tcpdump -i lo0 -nn -c 20 port 8080

# ② 只抓 SYN 和 FIN(看握手挥手)
sudo tcpdump -i lo0 -nn -c 20 'tcp port 8000 and (tcp[tcpflags] & tcp-syn != 0 or tcp[tcpflags] & tcp-fin != 0)'

# ③ 抓完整包存文件,事后拖到 Wireshark 看
sudo tcpdump -i lo0 -nn -s 0 -w demo.pcap port 9100

⚠️ 过滤表达式要用引号包起来 ,否则 shell 会把 (、)、! 当成 shell 语法解释掉,报错。


二、Wireshark 速查(操作向)

Wireshark 是图形版的 tcpdump,分析 pcap 文件时比命令行舒服十倍。记住四个用法就够:

功能 过滤语法 什么时候用
按端口过滤 tcp.port == 8080 只看某个服务的包
只看 HTTP http 看应用层请求
只看 SYN 包 tcp.flags.syn == 1 抓握手
只看重传 tcp.analysis.retransmission 排查丢包
追一条连接 右键某包 → Follow → TCP Stream 把一次交互的所有包按顺序拼出来
IO 图 统计 → IO Graph 看带宽随时间的变化

着色规则(不同状态的包用不同颜色标出来)和专家信息(Expert Information,自动标红重传/零窗口等异常)是 Wireshark 最值钱的两个功能,别的工具替代不了。


三、实战 1:抓三次握手和四次挥手

3.1 实验设计

自己写一个 echo 服务端,再写一个客户端 connect → send → close。连接建立和关闭的过程就是标准的三次握手 + 四次挥手。

服务端 echo_server.py:

python 复制代码
import socket
import threading

HOST, PORT = "127.0.0.1", 9100


def handle(conn, addr):
    try:
        data = conn.recv(1024)
        conn.sendall(b"pong:" + data)
    finally:
        conn.close()


def main():
    srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    srv.bind((HOST, PORT))
    srv.listen(128)
    print(f"echo 服务端 {HOST}:{PORT}")
    while True:
        conn, addr = srv.accept()
        threading.Thread(target=handle, args=(conn, addr), daemon=True).start()


if __name__ == "__main__":
    main()

3.2 抓包命令

另开一个终端,先起抓包,再起客户端:

bash 复制代码
# 终端 A:先抓包(只看 9100 端口的 SYN/FIN/RST,抓 10 个就停)
sudo tcpdump -i lo0 -nn -c 10 'tcp port 9100 and (tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0)'

# 终端 B:起服务端
python3 echo_server.py

# 终端 C:发起一次连接
python3 -c "
import socket
s = socket.socket()
s.connect(('127.0.0.1', 9100))
s.sendall(b'hi')
print(s.recv(100))
s.close()
"

3.3 抓到的握手挥手长什么样(典型输出)

tcpdump 抓到的 SYN/SYN+ACK/ACK 三个包,典型长这样(字段顺序:时间 源 → 标志 flags 选项):

text 复制代码
12:34:56.000000 IP 127.0.0.1.58118 > 127.0.0.1.9100: Flags [S], seq 1000, win 65535, options [mss 16344,...], length 0
12:34:56.000100 IP 127.0.0.1.9100 > 127.0.0.1.58118: Flags [S.], seq 2000, ack 1001, win 65535, options [mss 16344,...], length 0
12:34:56.000200 IP 127.0.0.1.58118 > 127.0.0.1.9100: Flags [.], ack 2001, win 65535, length 0

逐字段拆:

行 标志 含义 SEQ/ACK 变化
1 [S] 客户端发 SYN,我要连接,我的初始序号是 1000 seq=1000
2 [S.] 服务器回 SYN+ACK,同意连接,我的初始序号是 2000,确认你的 1001 seq=2000, ack=1001
3 [.] 客户端 ACK 服务器,确认你的 2001 ack=2001

🔴 重点看 SEQ/ACK 的增量:SYN 和 FIN 各占一个序号。所以客户端第一次发的 SEQ 是 1000,服务器回的 ACK 就是 1001(=1000+1);服务器自己的 SYN 是 2000,客户端回的 ACK 就是 2001。这个"+1"是面试和排错高频考点。

挥手时的四个包([F] 是 FIN,[.] 是 ACK):

text 复制代码
客户端 > 服务器: Flags [F.], seq 3000, ack 2001   # 客户端说"我没数据要发了"
服务器 > 客户端: Flags [.], ack 3001              # 服务器说"知道了"
服务器 > 客户端: Flags [F.], seq 2001, ack 3001   # 服务器说"我也没数据了"
客户端 > 服务器: Flags [.], ack 2002              # 客户端说"知道了,拜拜"

为什么是四次?因为服务器收到客户端 FIN 时,可能还有数据没发完,所以先回 ACK 表示"你的我收到了",等自己数据发完再发 FIN。ACK 和 FIN 不能合并。

3.4 用 netstat 观察状态变化(不需要 sudo)

本机非 root 环境用 netstat 也能看到连接状态。连接建立瞬间跑:

bash 复制代码
netstat -an -p tcp | grep 9100

实测一次 close 后看到的状态(客户端主动关):

text 复制代码
tcp4       0      0  127.0.0.1.9100         127.0.0.1.58118        FIN_WAIT_2
tcp4       7      0  127.0.0.1.58118        127.0.0.1.9100         CLOSE_WAIT
tcp4       0      0  127.0.0.1.9100         *.*                    LISTEN

🔴 这两行是排错金矿:

  • CLOSE_WAIT 出现在被动关闭方 。出现一堆 CLOSE_WAIT 说明你的应用没调 close()------recv 都返回了,代码忘了关 socket,操作系统就一直帮你停在 CLOSE_WAIT。
  • FIN_WAIT_2 出现在主动关闭方,在等对方的 FIN。正常很快就过去;堆积说明对方没关连接。

四、实战 2:抓丢包和重传

4.1 怎么模拟丢包

Linux 用 tc netem 一行命令丢包;macOS 用 dnctl(需 sudo):

bash 复制代码
# Linux:lo0 上丢 30% 的包
sudo tc qdisc add dev lo0 root netem loss 30%

# 抓包时重点看 tcp.analysis.retransmission(Wireshark 过滤)

4.2 重传的两种触发方式

TCP 重传不是只有一种,抓包能看到两种完全不同的现象:

类型 触发条件 抓包特征 速度
快速重传 收到 3 个重复 ACK(说明中间某个包丢了,但后面的包到了) 立刻重传丢失的那个包,不用等超时 快(毫秒级)
超时重传 超过 RTO(RTO 一般 200ms~几秒,会指数退避)还没收到 ACK 重传最后一个未确认的包,RTO 翻倍 慢(指数退避)

🔴 快速重传为什么要等 3 个重复 ACK 而不是 1 个? 因为 1 个重复 ACK 可能只是乱序到了,3 个重复 ACK 基本可以断定中间丢包了,不用傻等超时。


五、实战 3:复现大量 TIME_WAIT 并调参

这是线上最经典的事故之一:客户端(或调用方)大量短连接,TIME_WAIT 堆积到几万,端口耗尽,新连接报 Cannot assign requested address。

5.1 复现脚本

客户端循环 300 次:connect → send → recv → close。每次都是客户端主动关闭,所以 TIME_WAIT 出现在客户端这一端。

python 复制代码
# short_conn_client.py
import socket

TARGET = ("127.0.0.1", 9100)
for i in range(300):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(TARGET)
    s.sendall(b"ping")
    s.recv(1024)
    s.close()
print("完成 300 次短连接")

5.2 实测结果

先跑一次基线:

bash 复制代码
netstat -an -p tcp | grep -c TIME_WAIT
# 19(系统本来就有的)

再跑 300 次短连接,立刻统计:

bash 复制代码
python3 short_conn_client.py 300
netstat -an -p tcp | grep 9100 | grep TIME_WAIT | wc -l

✅ 实测输出:

text 复制代码
完成 300 次短连接
     323

300 次短连接,留下 323 个 TIME_WAIT(比 300 多一点是因为上一轮实验还没消散完)。抽几条看:

text 复制代码
tcp4       0      0  127.0.0.1.9100         127.0.0.1.57757        TIME_WAIT
tcp4       0      0  127.0.0.1.9100         127.0.0.1.57758        TIME_WAIT
tcp4       0      0  127.0.0.1.9100         127.0.0.1.57759        TIME_WAIT
tcp4       0      0  127.0.0.1.9100         127.0.0.1.57760        TIME_WAIT
tcp4       0      0  127.0.0.1.9100         127.0.0.1.57761        TIME_WAIT

看右边那个端口:57757、57758、57759......每次 connect 都消耗一个临时端口。

5.3 TIME_WAIT 为什么有害

TIME_WAIT 要持续 2MSL 才消失(msl = 最长分节生命期)。实测 macOS 的 MSL:

bash 复制代码
sysctl net.inet.tcp.msl
# net.inet.tcp.msl: 15000    (单位 ms,即 15 秒,2MSL = 30 秒)

⚠️ 危害:

  1. 端口耗尽:本机临时端口范围是有限的。macOS 默认:
bash 复制代码
sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last
# net.inet.ip.portrange.first: 49152
# net.inet.ip.portrange.last:  65535

总共才 65535 - 49152 = 16383 个临时端口。如果每秒建 1000 个短连接,30 秒的 TIME_WAIT 窗口里最多能扛 16383 / 30 ≈ 546 次/秒,超了就报 Cannot assign requested address。

  1. 内存占用:每个 TIME_WAIT 在内核里占一个 socket 结构,几万个就是几 MB,量大了也伤。

5.4 怎么调

手段 做什么 注意
用长连接 连接池复用,别每次都 connect/close 治本,优先做
扩大端口范围 把 ip_local_port_range 往前调 治标,Linux: sysctl -w net.ipv4.ip_local_port_range="10240 65535"
tcp_tw_reuse(Linux) 允许新连接复用 TIME_WAIT 的端口 需要 timestamps 打开;macOS 没有这个参数
服务端主动关 vs 客户端主动关 让 TIME_WAIT 出现在客户端而不是服务器 服务器端尽量被动关

🔴 核心结论 :TIME_WAIT 是设计来保护连接的(防止旧连接的迟到包被新连接当成自己的),不是 bug。正确做法是别让它产生(用长连接),而不是想办法把它干掉。


六、实战 4:拔网线/断电/崩溃对连接的影响

6.1 场景

TCP 连接建立后,一端直接拔网线(不发 FIN,断电)。对端完全不知道连接已经死了。
服务器 客户端 服务器 客户端 #mermaid-svg-FqPQoF6c0UqjvHsw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FqPQoF6c0UqjvHsw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FqPQoF6c0UqjvHsw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FqPQoF6c0UqjvHsw .error-icon{fill:#552222;}#mermaid-svg-FqPQoF6c0UqjvHsw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FqPQoF6c0UqjvHsw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FqPQoF6c0UqjvHsw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FqPQoF6c0UqjvHsw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FqPQoF6c0UqjvHsw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FqPQoF6c0UqjvHsw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FqPQoF6c0UqjvHsw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FqPQoF6c0UqjvHsw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FqPQoF6c0UqjvHsw .marker.cross{stroke:#333333;}#mermaid-svg-FqPQoF6c0UqjvHsw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FqPQoF6c0UqjvHsw p{margin:0;}#mermaid-svg-FqPQoF6c0UqjvHsw .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FqPQoF6c0UqjvHsw text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-FqPQoF6c0UqjvHsw .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-FqPQoF6c0UqjvHsw .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-FqPQoF6c0UqjvHsw .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-FqPQoF6c0UqjvHsw .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-FqPQoF6c0UqjvHsw #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-FqPQoF6c0UqjvHsw .sequenceNumber{fill:white;}#mermaid-svg-FqPQoF6c0UqjvHsw #sequencenumber{fill:#333;}#mermaid-svg-FqPQoF6c0UqjvHsw #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-FqPQoF6c0UqjvHsw .messageText{fill:#333;stroke:none;}#mermaid-svg-FqPQoF6c0UqjvHsw .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FqPQoF6c0UqjvHsw .labelText,#mermaid-svg-FqPQoF6c0UqjvHsw .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-FqPQoF6c0UqjvHsw .loopText,#mermaid-svg-FqPQoF6c0UqjvHsw .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-FqPQoF6c0UqjvHsw .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-FqPQoF6c0UqjvHsw .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-FqPQoF6c0UqjvHsw .noteText,#mermaid-svg-FqPQoF6c0UqjvHsw .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-FqPQoF6c0UqjvHsw .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FqPQoF6c0UqjvHsw .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FqPQoF6c0UqjvHsw .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FqPQoF6c0UqjvHsw .actorPopupMenu{position:absolute;}#mermaid-svg-FqPQoF6c0UqjvHsw .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-FqPQoF6c0UqjvHsw .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FqPQoF6c0UqjvHsw .actor-man circle,#mermaid-svg-FqPQoF6c0UqjvHsw line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-FqPQoF6c0UqjvHsw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 连接正常建立 服务器突然断电/拔网线没发 FIN A 不知道 B 已死,继续发 重试 N 次还没 ACK 数据继续发数据...重传第 1 次(超时后)重传第 2 次应用层超时,报错关闭

6.2 应用层怎么感知连接死了

TCP 自带的 Keepalive 默认 2 小时才开始探测,根本等不起。真正线上做法:

机制 谁实现 探测间隔 灵敏度
TCP Keepalive 内核 默认 2 小时才开始发探测包 慢到没用
应用层心跳 自己写 30~60 秒 快,可定制

🔴 结论:别指望 TCP Keepalive 帮你发现死连接。要自己在应用层做心跳:每隔 N 秒发一个心跳包,连续 M 次没响应就判定死了,主动关闭并重连。


七、实战 5:Keepalive 与 Keep-Alive 的区别

这俩名字像,其实完全是两个东西,面试和工作中都有人搞混。

维度 TCP Keepalive HTTP Keep-Alive
层级 传输层(TCP) 应用层(HTTP)
目的 探测连接是否还活着 复用 TCP 连接发多个 HTTP 请求
怎么做 连接空闲 N 小时后,发空 ACK 探测 一个 TCP 连接上顺序发多个 HTTP 请求
触发 内核自动 浏览器/客户端 Connection: keep-alive
默认值 2 小时空闲才开始(实测 macOS:net.inet.tcp.keepidle: 7200000 ms = 2 小时) HTTP/1.1 默认开启
失败后果 连接被判定死了,关闭 换个连接重新发

实测 macOS 默认值:

bash 复制代码
sysctl net.inet.tcp.keepidle net.inet.tcp.keepintvl net.inet.tcp.keepcnt
# net.inet.tcp.keepidle: 7200000     (空闲多久才开始探测,毫秒)
# net.inet.tcp.keepintvl: 75000     (探测包间隔,毫秒)
# net.inet.tcp.keepcnt: 8           (最多探测几次)

🔴 一句话区分 :Keepalive(TCP)是"看对方还活着没",Keep-Alive(HTTP)是"这条 TCP 连接别着急关,我还要发下一个请求"。一个管死活,一个管复用。


八、经典问题:TCP 到底丢不丢?

面试最爱问:"TCP 是不是保证不丢包?"标准答案:不是绝对不丢,是"连接正常的情况下保证按序、不丢、不重复"。

情况 TCP 能保证吗
网络正常,连接还在 ✅ 按序、不丢、不重复到达应用层
中间路由器短暂丢包 ✅ 重传补上,应用层无感知
一端拔网线/断电/崩溃 ❌ 已发但未 ACK 的数据可能真的丢了
中间 NAT 设备把表项清了 ❌ 连接静默死了,双方都不知道

TCP 的"可靠"是尽力而为 + 通知:它会重传、会校验、会排序,但如果底层连接本身没了,它也变不出数据来。

🔴 应用层必须自己兜底:

  1. 业务确认机制:重要操作要有应用层 ACK,不能光靠 TCP。
  2. 重试 + 幂等:网络抖动时客户端要能安全重试(接口设计成幂等)。
  3. 事务/状态机:钱的事,别赌 TCP。

九、抓包分析速查表

线上抓包看到这些现象,按这张表查:

抓包看到 可能原因 解决方向
大量 [S] 但没有 [S.] 目标没起 / 防火墙挡了 / backlog 满了 查服务是否监听、查防火墙、调 somaxconn
大量 [S.] 但没有第三个 [.] 客户端到服务器的回程路不通 / 防火墙丢包 查回程路由、查 conntrack 表满
大量 [.] 但数据卡住 对端窗口为 0(零窗口) 接收方应用读太慢,查消费端
重复 ACK 三连 中间丢包 快速重传会救,持续丢查链路
RTO 重传多 链路质量差 / 跨机房延迟高 查丢包率、调 RTO
大量 TIME_WAIT 短连接太多 上连接池、调端口范围
大量 CLOSE_WAIT 应用忘了 close() 查代码,谁没关 socket
大量 FIN_WAIT_2 对方不关闭连接 查对方是不是崩溃/阻塞
RST 突然出现 连接被强制重置(进程崩、防火墙杀) 查对端日志、查防火墙

总结:你真正需要记住的 8 件事

  1. tcpdump 三剑客 :-i lo0 指定接口、-nn 不解析、port X 过滤端口,再加 -c 限量。
  2. 抓握手看 SYN/SYN+ACK/ACK,SEQ 各 +1(SYN 和 FIN 各占一个序号)。
  3. 四次挥手不能合并:因为服务器收到 FIN 时可能还有数据没发完。
  4. TIME_WAIT 出现在主动关闭方 ,持续 2MSL,短连接太多会把端口耗尽------用长连接治本。
  5. CLOSE_WAIT 堆积 = 你代码忘了 close(),不是网络问题。
  6. 快速重传靠 3 个重复 ACK,超时重传靠 RTO 指数退避,抓包特征完全不同。
  7. TCP Keepalive(2 小时)和 HTTP Keep-Alive(连接复用)是两码事,别搞混。
  8. TCP 不是绝对不丢:连接断了就是断了,应用层要自己做心跳、重试、幂等。

验证清单

  • 能不查资料写出"抓 8080 端口、不解析、抓 10 个包"的 tcpdump 命令
  • 能说清 SYN/SYN+ACK/ACK 三个包各自的 SEQ 和 ACK 是多少
  • 能复现 300 次短连接产生大量 TIME_WAIT
  • 能说出本机临时端口范围是多少、耗尽会报什么错
  • 看到一堆 CLOSE_WAIT 能第一反应"应用没 close"
  • 能区分快速重传和超时重传的触发条件
  • 能一句话说清 TCP Keepalive 和 HTTP Keep-Alive 的区别
  • 能说清为什么 TCP 不是"绝对不丢"

参考资源


下一篇《【计算基础|网络13】UDP 与可靠传输》讲:UDP 首部为什么只有 8 字节、UDP 为什么不可靠但还满世界在用、怎么在 UDP 上自己实现可靠传输(QUIC 的思路)、以及"同一个端口能不能同时被 TCP 和 UDP 监听"这个经典面试题。

相关推荐
zoyation1 小时前
jrp 1.2.0 重磅发布|P2P打洞直连 · 端口自动分配 · 一端口多服务,这次全齐了!
网络·网络协议·p2p
励志师code1 小时前
RoCE 网络实战:从 NCCL 调优到 RDMA 硬件计数器排障
linux·运维·网络·云计算
砚凝霜1 小时前
【软考信息安全】第二十一章 网络设备安全增强技术与漏洞防护
网络·安全·web安全
Alinket2 小时前
毫米波雷达 vs 摄像头 vs 手环:养老跌倒监测三类方案怎么选
网络·数据库·健康医疗·信息与通信·iot
企业解惑小助手2 小时前
大型企业终端如何统一管理排障实录:批量终端策略不生效问题排查
运维·服务器·网络·域智盾软件
盛世宏博智慧档案2 小时前
IP 温湿度设备频繁断连?TCP 心跳保活机制调试与参数设置指南
网络·网络协议·tcp/ip·php·传感器·温湿度
Gigavision2 小时前
CAS(ME)²数据集 感知图卷积网络算法 CAS(ME)²数据集下载
网络·算法
aodunsoft2 小时前
安全月报 | 傲盾DDoS攻击防御2026年9月简报
网络·安全·ddos
花间相见2 小时前
【计算基础|网络11】TCP(下):拥塞控制与参数优化
网络·tcp/ip·策略模式