ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

计算机网络自顶向下运输层:TCP/UDP抓包与代码实战

计算机网络自顶向下运输层:TCP/UDP抓包与代码实战 简介这份PPT课件面向计算机专业学生及网络初学者系统讲解计算机网络体系结构中的运输层核心知识帮助读者从自顶向下的视角理解端到端通信机制。内容围绕运输层服务展开涵盖多路复用与多路分解、UDP无连接传输、TCP面向连接传输、可靠数据传输原理、流量控制、拥塞控制原则及TCP拥塞控制机制等模块并配有rdt1至rdt3协议演进、回退N帧、选择重传、TCP吞吐量与公平性等具体知识点适合课堂学习与期末复习对照使用。资源包共1个文件为ppt格式压缩包大小约1.82MB结构紧凑便于直接打开浏览。目前已有58人学习下载可作为运输层章节的配套讲义帮助读者梳理协议运行逻辑、掌握TCP与UDP的差异及拥塞控制思路。1. 从一份“计算机网络自顶向下.ppt”说起运输层到底该怎么学才不飘很多人手里都有一份“计算机网络自顶向下.ppt”可能是老师发的课件也可能是从各种渠道攒来的复习资料。打开一看应用层、运输层、网络层、链路层一路铺开图多、箭头多、术语密翻到运输层那一叠幻灯片时TCP 三次握手、四次挥手、UDP 无连接、端口复用这些词全挤在一起看着都认识合上就说不清。问题不在你记性差而在这份 PPT 的定位是“课堂提纲”它负责把知识铺开不负责把一条报文从你的键盘送到对面主机再送回来。真正让运输层立住的是把它当成一个可观测、可复现的系统TCP 连接怎么建、UDP 数据报怎么发、端口怎么复用、丢包和乱序长什么样。这篇笔记就围绕这份 PPT 里运输层那部分把概念、抓包验证、代码复现和踩坑一次讲透适合正在啃自顶向下教材、准备考试或者刚上手写网络程序的人。2. 运输层在自顶向下体系里的位置为什么 TCP 和 UDP 是两条路自顶向下的讲法是从应用层往下走到了运输层你第一次真正碰到“端到端”这件事。应用层的 HTTP、DNS、视频流最终都要交给运输层由它决定用 TCP 还是 UDP 把数据送出去。这一章先把两条路的定位讲清楚再落到端口、复用和分用这些 PPT 里一笔带过但考试和写代码都绕不开的点。2.1 TCP 与 UDP 的分工可靠字节流 vs 数据报TCP 提供的是面向连接的、可靠的、基于字节流的服务。它把应用层交下来的数据看成没有边界的字节流自己切段、编号、确认、重传、排序最后按序交给对端应用。UDP 提供的是无连接的、尽最大努力交付的数据报服务它保留应用层报文的边界发出去就不管了丢不丢、乱不乱、重不重运输层不负责。这个差别决定了选型。文件传输、网页、邮件这类不能丢数据的场景用 TCP实时语音、视频、DNS 查询、游戏状态同步这类“宁可丢一点也不能等”的场景用 UDP。PPT 上通常只写一句“TCP 可靠、UDP 不可靠”但真正要理解的是可靠性不是免费的它靠序号、确认、重传、窗口、拥塞控制一整套机制换来的代价是延迟和开销。对比项TCPUDP连接面向连接需三次握手无连接直接发可靠性确认重传按序交付不保证到达和顺序数据边界字节流无边界保留报文边界首部开销20 字节起8 字节典型应用HTTP、FTP、SMTPDNS、DHCP、实时音视频2.2 端口、复用与分用一台主机怎么同时跑这么多连接运输层用端口号来区分同一台主机上的不同应用进程。16 位端口号0 到 65535其中 0 到 1023 是熟知端口1024 到 49151 是登记端口49152 到 65535 是临时端口。复用是发送方多个应用进程共用运输层分用是接收方运输层根据端口把数据交给正确的进程。这里有个常被忽略的点TCP 连接由四元组唯一标识源 IP、源端口、目的 IP、目的端口。所以同一台主机上一个服务监听 80 端口可以同时接受成千上万个连接因为每个连接的四元组不同。UDP 没有连接分用只看目的端口所以两个进程不能绑同一个 UDP 端口但可以用 SO_REUSEADDR 做地址复用这个后面踩坑章节会细说。提示考试里常问“一个 TCP 连接能不能同时被两个进程使用”答案是不能四元组唯一但一个监听套接字可以派生出多个已连接套接字。2.3 从 PPT 到抓包把三次握手和四次挥手看成报文序列PPT 上画的三次握手是 SYN、SYNACK、ACK四次挥手是 FIN、ACK、FIN、ACK。光背顺序没用得知道每个报文里带了什么。SYN 报文会带初始序号 seqxSYNACK 带 seqy、ackx1第三次 ACK 带 acky1。挥手时 FIN 表示“我没有数据要发了”但还能收所以是半关闭两边都发 FIN 才彻底关。用 tcpdump 或 Wireshark 抓一次本机访问网页的过程你能直接看到这些报文。下面这条命令抓本机 80 或 443 端口的 TCP 报文-n 不解析域名-S 显示绝对序号方便对照 PPT 上的 x、y。# 抓取与 93.184.216.34 的 TCP 交互只看前 20 个包 sudo tcpdump -i any -n -S tcp and host 93.184.216.34 -c 20参数说明-i any 监听所有网卡-n 不做 DNS 反解-S 显示绝对序号而不是相对序号-c 20 抓满 20 个包退出。抓完对照 Flags 字段[S] 是 SYN[S.] 是 SYNACK[.] 是 ACK[F.] 是 FINACK。这一步做完PPT 上那几张握手图就不再是抽象箭头了。3. 用代码把 TCP 和 UDP 跑起来最小可复现实验光看抓包还不够自己写一遍才知道 API 和协议字段怎么对应。这一章用 Python 写最小 TCP 服务端客户端和 UDP 收发再讲 iperf3 打流和 UDP 分片这两个高频场景。代码都能直接跑参数怎么调、失败看什么一并说清。3.1 最小 TCP 回显服务accept、recv、send 的对应关系先写服务端。socket 创建、bind、listen、accept、recv、send、close这几步和 PPT 上运输层提供的接口一一对应。bind 绑定端口就是分用的入口listen 把套接字变成被动打开accept 返回的是新的已连接套接字四元组已经确定。import socket # 创建 TCP 套接字AF_INET 表示 IPv4SOCK_STREAM 表示字节流 server socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 允许地址复用避免重启时 TIME_WAIT 导致 bind 失败 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((0.0.0.0, 9000)) # 绑定所有网卡的 9000 端口 server.listen(5) # 半连接队列长度 5 print(listening on 9000) while True: conn, addr server.accept() # 阻塞直到有连接返回新套接字和对端地址 print(connected from, addr) data conn.recv(1024) # 最多收 1024 字节TCP 是字节流不保证一次收完 if data: conn.sendall(data) # 回显sendall 保证全部发完 conn.close() # 关闭已连接套接字触发四次挥手逻辑说明accept 返回的 conn 是新的套接字原 server 继续监听。recv 返回空字节表示对端关闭。sendall 内部循环调用 send直到所有数据进入发送缓冲区。参数上listen 的 5 是 backlogLinux 下实际队列长度还受 somaxconn 影响高并发场景要调大。客户端对应写import socket client socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((127.0.0.1, 9000)) # 触发三次握手 client.sendall(bhello transport layer) resp client.recv(1024) print(echo:, resp) client.close() # 触发四次挥手connect 返回时三次握手完成close 时如果还有数据没发完内核会尝试发完再挥手。想看握手和挥手就在客户端 connect 前后用 tcpdump 抓 9000 端口。3.2 最小 UDP 收发sendto、recvfrom 与报文边界UDP 的 API 更直接没有连接每次 sendto 指定目的地址recvfrom 返回数据和来源地址。注意 UDP 保留报文边界一次 sendto 对应一次 recvfrom缓冲区小了会截断。import socket # UDP 服务端 server socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server.bind((0.0.0.0, 9001)) while True: data, addr server.recvfrom(2048) # 一次收一个数据报 print(from, addr, len, len(data)) server.sendto(data.upper(), addr) # 原样返回大写import socket client socket.socket(socket.AF_INET, socket.SOCK_DGRAM) client.sendto(budp test, (127.0.0.1, 9001)) data, addr client.recvfrom(2048) print(reply:, data) client.close()参数说明recvfrom 的 2048 是接收缓冲区大小如果数据报大于这个值多余部分被丢弃且没有通知。UDP 首部里的长度字段是 16 位所以一个 UDP 数据报最大 65535 字节减去 IP 首部和 UDP 首部实际载荷更小。超过 MTU 会触发 IP 分片这就是热词里“udp 划分 ip 数据报片”的来源。3.3 iperf3 打流与 UDP 分片观察测吞吐常用 iperf3。TCP 模式直接跑UDP 模式要指定带宽否则默认 1Mbps 看不出问题。# 服务端 iperf3 -s # 客户端 TCP 测试跑 10 秒 iperf3 -c 192.168.1.10 -t 10 # 客户端 UDP 测试目标 100Mbps报文长度 1400 iperf3 -c 192.168.1.10 -u -b 100M -l 1400 -t 10参数说明-u 用 UDP-b 指定目标带宽-l 指定报文长度。把 -l 设成 1400 通常不触发分片设成 3000 就会分片。想看分片在服务端抓包过滤udp and port 5201Wireshark 里会看到 IP 层有 “Fragmented IP protocol” 标记。分片带来的问题是任何一片丢了整个数据报都废重传只能靠应用层所以实时音视频一般把载荷控制在 MTU 以下避免分片。注意UDP 分片后接收端要等所有片到齐才能重组重组有超时超时整个数据报丢弃。这就是为什么大 UDP 包在弱网下丢包率会陡增。4. 运输层避坑与排查那些 PPT 不会写的翻车现场这一章全是血泪经验。PPT 讲原理不讲你 bind 失败、连接卡死、UDP 收不到包时该看什么。下面五条按“现象 → 原因 → 解决”写都是实际调试中反复遇到的。4.1 bind 报 Address already in use现象服务端重启时 bind 报OSError: [Errno 98] Address already in use明明进程已经退了。原因TCP 主动关闭方会进入 TIME_WAIT持续 2MSL通常是 60 秒。这段时间四元组还被内核占着新进程 bind 同一端口就失败。解决设置 SO_REUSEADDR允许绑定处于 TIME_WAIT 的地址。代码里server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)放在 bind 之前。注意 SO_REUSEADDR 和 SO_REUSEPORT 不同后者允许多个进程绑同一端口做负载均衡Linux 3.9 以后支持但行为要谨慎。4.2 TCP 连接建立成功但收不到数据现象客户端 connect 成功send 也返回了服务端 accept 到了连接但 recv 一直阻塞。原因常见有两种。一是服务端 accept 后没有继续 recv数据在接收缓冲区里二是客户端 send 后没发 FIN服务端 recv 在等更多数据。TCP 是字节流recv 返回 0 才表示对端关闭返回正数只表示收到了这么多字节不表示消息结束。解决应用层自己定边界比如固定长度、长度前缀或分隔符。调试时用ss -tnp看连接状态和收发队列ss -tn state established能看到 Recv-Q 和 Send-Q队列有积压说明对端没读。4.3 UDP 收不到包但抓包能看到现象tcpdump 抓到 UDP 包到了网卡但应用层 recvfrom 一直阻塞。原因可能是防火墙拦了也可能是绑定了错误的地址。bind 到 127.0.0.1 就只能收本机回环的包外部网卡来的包收不到。还有可能是接收缓冲区溢出内核直接丢包应用层无感知。解决先确认 bind 地址是 0.0.0.0 还是具体网卡 IP。用ss -ulnp看 UDP 监听状态和 Recv-Q如果 Recv-Q 经常非零说明应用读得慢调大 SO_RCVBUF。防火墙用 iptables 或 firewalld 查对应端口。4.4 三次握手成功但 TLS 握手失败现象TCP 层抓包看到三次握手正常但应用层报连接重置或超时。原因这通常不是运输层问题而是应用层协议不匹配比如客户端发 HTTP 请求服务端等 TLS ClientHello。也可能是中间设备改了报文。解决抓包看握手后第一个应用层报文的内容确认协议一致。运输层只负责把字节送到不关心里面是什么。排查时先分层TCP 通了就往上查。4.5 大量 TIME_WAIT 导致端口耗尽现象压测时客户端报Cannot assign requested addressss 一看大量 TIME_WAIT。原因客户端主动关闭连接每个连接占一个临时端口TIME_WAIT 期间不能复用端口范围有限高并发短连接很快耗尽。解决用连接池复用连接或者让服务端主动关闭。也可以调内核参数net.ipv4.tcp_tw_reuse1允许复用 TIME_WAIT 连接但只在客户端有效且时间戳开启时安全。根本办法还是减少短连接。5. 把运输层学扎实的进阶技巧从抓包到协议栈参数学到这一步PPT 上的知识点已经能对应到实际报文和代码了。再往上走有两个方向值得投入一是用抓包和工具验证每一个机制二是理解操作系统协议栈的可调参数知道边界在哪。先说验证。三次握手、四次挥手、重传、滑动窗口、拥塞控制这些都能在 Wireshark 里看到。重传看 TCP Retransmission 标记滑动窗口看 Window Size 字段拥塞控制看 cwnd 变化Linux 下用ss -ti能看到每个连接的 cwnd、rtt、retrans 计数。下面这条命令看已建立连接的详细 TCP 信息ss -ti state established ( dport :443 or sport :443 )输出里的 cwnd、rtt、retrans 就是协议栈内部状态比看 PPT 上的曲线直观得多。想复现拥塞控制用 iperf3 打流同时用 ss 观察 cwnd 从慢启动到拥塞避免的变化丢包时 cwnd 会掉这就是 PPT 上那张锯齿图的来源。再说参数。Linux 协议栈有一堆可调项sysctl -a | grep tcp能看到。常用的几个net.ipv4.tcp_syncookies防 SYN Floodnet.ipv4.tcp_max_syn_backlog调半连接队列net.core.somaxconn调 accept 队列net.ipv4.tcp_rmem和tcp_wmem调收发缓冲区。这些参数不是背的是遇到问题时查的。比如高并发下 accept 慢先看 somaxconn 和 backlog 是否够。参数作用常见调整net.core.somaxconnaccept 队列上限高并发调到 4096net.ipv4.tcp_max_syn_backlog半连接队列防 SYN Flood 调大net.ipv4.tcp_tw_reuse复用 TIME_WAIT客户端短连接可开net.ipv4.tcp_rmem接收缓冲区高带宽延迟积调大最后说一个我自己的习惯每学一个运输层机制就写一段最小代码或抓一次包去验证它。三次握手就抓 connect四次挥手就抓 closeUDP 分片就把报文设大再抓。PPT 是地图抓包和代码是走路走一遍才知道哪里是坑。我当初就是靠反复抓包才把 TIME_WAIT 和 CLOSE_WAIT 分清CLOSE_WAIT 多说明应用没 closeTIME_WAIT 多说明主动关闭太频繁这两个状态在 ss 里一眼就能看出来。希望帮到你。本文还有配套的精品资源点击获取
返回列表