尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

计算机网络基础知识实战:从OSI七层到TCP三次握手与排障

计算机网络基础知识实战:从OSI七层到TCP三次握手与排障 简介这份PDF资料面向准备技术面试的IT求职者与网络初学者系统梳理计算机网络核心考点帮助读者在面试与工程实践中快速定位知识盲区。内容围绕OSI七层参考模型与TCP/IP四层模型展开涵盖TCP/IP协议族、TCP/UDP/SCTP协议对比、三次握手与四次挥手、TCP状态机、TIME_WAIT状态、端口号、超时重传与快速重传、TCP Header结构、可靠传输、流量控制与拥塞控制以及IPv4、IPv6、ICMP、ARP、RARP、IGMP等网络层协议并附常见面试问题解析。资源包共1个PDF文件约2.08MB结构按章节递进便于按模块查阅与复习。目前已有969人学习适合需要系统梳理网络知识体系、对照面试高频题查漏补缺的读者。1. 计算机网络基础知识从一根网线到一次 HTTP 请求中间到底发生了什么很多人对「计算机网络基础知识」的印象停留在背 OSI 七层模型、记 TCP 三次握手考完就忘。但真正让一线工程师翻车的往往不是这些概念本身而是概念和现实对不上号明明 ping 得通却连不上服务明明 TCP 建连成功却收不到响应明明代码里 bind 了端口却报「address already in use」。这些问题的根因几乎都能回溯到分层模型里某一层的职责边界没搞清楚。这篇笔记不打算把《计算机网络》教材重讲一遍而是按「一个数据包从应用层发出到对端应用层收到」这条真实链路把 OSI 七层模型、TCP/IP 四层模型、TCP 三次握手、端口与连接状态这些核心知识点落到能动手验证的命令和能复现的代码上。适合两类人一是正在学计算机网络、想摆脱死记硬背的在校生二是做后端、DevOps、嵌入式联网比如 Modbus TCP、ESP 模块发 TCP 消息时被网络问题卡住的工程师。读完你应该能做到看到一个网络故障先判断它大概率出在哪一层再用对应工具去验证而不是盲目重启。2. OSI 七层与 TCP/IP 四层分层设计到底解决了什么问题2.1 为什么要有分层一次「改一层不影响另一层」的工程妥协分层设计的本质是关注点分离。假设没有分层你要写一个「通过网线把文件传到另一台机器」的程序就得同时处理网卡电气信号、帧的起止、IP 寻址、路由选择、丢包重传、数据顺序、字符编码……任何一处改动都可能牵动全身。分层之后每一层只对上一层提供服务只依赖下一层的接口。最直接的好处是你换一块网卡物理层、链路层变了上层的 TCP 代码一行都不用改你把 HTTP 换成 WebSocket应用层变了底下的 TCP/IP 照样跑。这就是热词里「体会分层设计」的真正含义——它不是让你背七层名字而是让你理解每一层可以独立替换。OSI 是理论参考模型分七层TCP/IP 是工程落地模型分四层。两者的对应关系是面试和排障的高频考点我整理成一张表OSI 七层TCP/IP 四层典型协议/设备这一层出问题的典型现象应用层 / 表示层 / 会话层应用层HTTP、DNS、Modbus、MQTT服务返回 4xx/5xx、域名解析失败传输层传输层TCP、UDP端口不通、连接被拒、丢包重传网络层网络层IP、ICMP、ARP部分ping 不通、路由不可达数据链路层网络接口层以太网、MAC、网卡驱动同网段不通、ARP 表异常物理层网络接口层网线、光模块、电信号网卡灯不亮、链路 down提示排障时从下往上查更省时间。物理层和链路层没问题网卡 up、能 ping 通网关再往上看 IP 和端口最后才怀疑应用代码。2.2 数据封装与解封装一个包是怎么被「套娃」的数据从上往下走叫封装每经过一层就加一个头部有时还有尾部。以一次 HTTP 请求为例应用层产生 HTTP 报文传输层加上 TCP 头含源端口、目的端口、序号变成 TCP 段网络层加上 IP 头含源 IP、目的 IP变成 IP 包链路层加上以太网头含源 MAC、目的 MAC和帧尾校验变成帧物理层把帧变成电信号/光信号发出去。对端收到后反向解封装每层剥掉自己的头把载荷交给上一层。理解这个过程你就能解释很多现象比如为什么抓包工具 Wireshark 能同时看到以太网头、IP 头、TCP 头和 HTTP 内容——因为它就是在链路层「截获」了完整的帧。2.3 用一条命令把分层「看」出来光讲理论容易飘动手验证一次印象最深。在 Linux/macOS 上用tracerouteWindows 用tracert可以看到数据包经过的每一跳这直接对应网络层的路由行为# -n 表示不反解域名直接显示 IP速度更快 # 目标可以是任意公网地址这里用常见的 DNS 服务器举例 traceroute -n 8.8.8.8 # 查看本机网络接口和 IP对应网络层和链路层 ip addr show # Linux ifconfig # macOS / 老版本 Linux # 查看 ARP 表对应链路层的 MAC 地址映射 arp -a逻辑说明traceroute利用 IP 包的 TTL 字段逐跳递增 TTL让沿途每个路由器回一个 ICMP 超时报文从而画出路径。ip addr看的是本机网络层地址IP和链路层状态网卡是否 UP。arp -a看的是 IP 到 MAC 的映射如果这里缺了网关的条目同网段通信就会出问题。参数说明-n关闭 DNS 反解排障时强烈建议加上否则每一跳都要等域名解析慢得让人怀疑人生。traceroute默认发 UDP 包某些网络会过滤可以换-I用 ICMP或-T用 TCP。3. TCP 三次握手与四次挥手连接到底是怎么建立和断开的3.1 三次握手每一步在干什么TCP 是面向连接的协议通信前必须先建连。三次握手的过程客户端发SYNseqx进入 SYN_SENT服务端回SYNACKseqy, ackx1进入 SYN_RCVD客户端回ACKacky1双方进入 ESTABLISHED。为什么是三次而不是两次核心原因是双方都要确认对方的收发能力都正常。两次握手只能让服务端确认「客户端能发、我能收」但客户端无法确认「服务端能发、我能收」。第三次 ACK 补上了这个确认。另外三次握手还能防止历史失效的连接请求突然到达服务端导致服务端建立无效连接、白白占用资源。3.2 用代码亲手触发一次握手理论看再多不如自己写一个最小 TCP 服务端和客户端用抓包看握手。下面是一个 Python 最小示例# server.py —— 最小 TCP 服务端 import socket # AF_INET 表示 IPv4SOCK_STREAM 表示 TCP server socket.socket(socket.AF_INET, socket.SOCK_STREAM) # SO_REUSEADDR 让端口在 TIME_WAIT 状态下也能快速复用避免重启报 address already in use server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((0.0.0.0, 9000)) # 监听所有网卡的 9000 端口 server.listen(5) # backlog 队列长度 5 print(listening on 9000) conn, addr server.accept() # 阻塞等待客户端连接这一步背后就是三次握手 print(connected from, addr) data conn.recv(1024) # 接收数据 print(recv:, data) conn.sendall(bhello from server) conn.close() server.close()# client.py —— 最小 TCP 客户端 import socket client socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((127.0.0.1, 9000)) # 触发三次握手 client.sendall(bhello from client) resp client.recv(1024) print(resp:, resp) client.close()逻辑说明accept()返回的那一刻三次握手已经完成连接进入 ESTABLISHED。connect()在客户端侧发起 SYN 并等待 SYNACK收到后才返回。SO_REUSEADDR是服务端必设项否则服务端主动关闭连接后进入 TIME_WAIT短时间内重启会报端口占用。参数说明listen(5)的 5 是 backlog表示已完成握手但还没被accept()取走的连接队列长度。高并发场景这个值要调大否则新连接会被丢弃。recv(1024)的 1024 是一次最多读多少字节TCP 是字节流不保证一次 recv 就读完一条完整消息这是新手最容易踩的坑。3.3 四次挥手与 TIME_WAIT关闭连接需要四次挥手因为 TCP 是全双工的每个方向要单独关闭主动关闭方发FIN被动方回ACK被动方数据发完后发FIN主动方回ACK并进入TIME_WAIT等待 2MSL 后彻底关闭。TIME_WAIT 常被误解为「bug」其实它是必要的一是保证最后一个 ACK 能到达对端二是让本次连接的残余报文在网络中消散避免影响下一个复用相同四元组的新连接。服务端如果出现大量 TIME_WAIT通常是它主动关闭了大量连接可以考虑用连接池或调整内核参数而不是简单粗暴地关掉 TIME_WAIT。用下面命令可以观察连接状态分布# 统计各 TCP 状态的数量排障时一眼看出问题 ss -ant | awk NR1 {print $1} | sort | uniq -c | sort -rn # 只看 9000 端口的连接 ss -ant sport :90004. 端口、连接与常见网络故障排查4.1 端口和四元组连接的唯一标识一条 TCP 连接由四元组唯一确定源 IP、源端口、目的 IP、目的端口。这也是为什么同一台机器可以用同一个本地端口连不同的服务或者用不同端口连同一个服务——只要四元组不同就是不同的连接。端口范围分三类0–1023 是知名端口HTTP 80、HTTPS 443、SSH 221024–49151 是注册端口49152–65535 是动态/临时端口。客户端connect()时如果不指定本地端口操作系统会从临时端口范围里分配一个。注意报错「address already in use」不一定是端口真被占用也可能是上一个连接处于 TIME_WAIT。用ss -ant看状态如果是 TIME_WAIT加SO_REUSEADDR即可如果是 LISTEN那才是真被别的进程占了。4.2 分层排障的固定套路我一般按这个顺序查基本能覆盖 90% 的问题物理/链路层网卡是否 UPip link网线灯是否亮同网段能否 ping 通。网络层能否 ping 通网关和目标 IPping路由是否正确ip route。传输层目标端口是否开放nc -zv host port或telnet host port本机是否在监听ss -tlnp。应用层服务日志、返回码、抓包看实际收发的数据tcpdump。# 测试目标端口是否可达-z 只探测不发送数据-v 显示详情 nc -zv 127.0.0.1 9000 # 查看本机所有监听中的 TCP 端口及对应进程 ss -tlnp # 抓取 9000 端口的包-i any 表示所有网卡-w 写入文件供 Wireshark 分析 sudo tcpdump -i any port 9000 -w tcp9000.pcap逻辑说明nc -zv走的是完整的 TCP 三次握手能连上说明传输层通。ss -tlnp里-t是 TCP-l是 LISTEN-n不解析服务名-p显示进程。tcpdump抓到的 pcap 文件可以用 Wireshark 打开直接看到三次握手的三个包这是验证理论最直观的方式。4.3 UDP 和 TCP 的选型边界热词里高频出现「UDP 和 TCP 的区别」这里给一个工程视角的判断标准而不是背特性表要可靠、有序、有连接选 TCPHTTP、数据库连接、文件传输、Modbus TCP。要低延迟、能容忍丢包、自己控制重传选 UDP实时音视频、DNS 查询、游戏同步、部分物联网上报。关键点UDP 不是「不可靠就不能用」而是把可靠性控制权交给了应用层。很多实时场景宁可丢一帧也不要卡顿这时 TCP 的重传机制反而是负担。5. 避坑与常见问题那些教材不会告诉你的翻车现场5.1 坑一ping 得通却连不上服务现象ping 目标IP正常但nc -zv 目标IP 端口超时或被拒。原因ping 走的是 ICMP属于网络层连服务走的是 TCP属于传输层。网络层通不代表传输层通——可能是目标端口没监听、被防火墙拦了、或服务只绑定了 127.0.0.1 而非 0.0.0.0。解决先在目标机ss -tlnp确认端口在监听且绑定地址正确再检查防火墙规则最后用tcpdump看 SYN 有没有到达、有没有回 RST。5.2 坑二recv 一次没读完就当成完整消息现象客户端发了一条 1000 字节的消息服务端recv(1024)却只收到 300 字节解析报错。原因TCP 是字节流协议没有消息边界。发送方的sendall和接收方的recv不是一一对应的网络会把数据切成任意大小的段。解决应用层自己定边界。常见做法是「长度前缀」先发 4 字节表示消息长度再发内容或「分隔符」如换行。这是写 TCP 程序必须处理的第一件事。5.3 坑三服务端重启报 address already in use现象刚 CtrlC 停掉服务立刻重启就报端口占用。原因服务端主动关闭连接后连接进入 TIME_WAIT默认持续 2MSLLinux 上约 60 秒期间端口不能被新连接绑定。解决设置SO_REUSEADDR见 3.2 的代码。注意它解决的是 TIME_WAIT 复用不是让两个进程同时监听同一端口。5.4 坑四把 OSI 七层当成必须严格对应的实现现象纠结「ARP 到底属于哪一层」「Modbus TCP 算应用层还是传输层」越想越乱。原因OSI 是理论参考模型实际协议栈并不严格按七层划分。ARP 横跨链路层和网络层Modbus TCP 是把 Modbus 报文封装进 TCP 载荷本质是应用层协议。解决把分层当成分析工具而非分类标准。排障时问「这个问题属于寻址、传输还是应用逻辑」比纠结它「属于第几层」有用得多。5.5 坑五抓包抓不到想要的流量现象tcpdump跑着却什么都没抓到。原因抓错了网卡比如服务在 eth0 却抓了 lo或者过滤表达式写错或者没有 sudo 权限。解决先用tcpdump -D列出所有网卡用-i any抓所有网卡过滤表达式先用最简单的port 9000验证再逐步加条件确认有 root 权限。6. 进阶技巧用一条命令验证你对 TCP 状态的全部理解学完理论怎么知道自己真懂了我的验证方法是不看任何资料用ss命令把一条连接从建立到关闭的完整状态变化复现出来。具体做法开两个终端。终端 A 跑一个服务端并让它保持连接不关闭终端 B 用nc连上去然后反复执行ss -ant | grep 9000观察状态从LISTEN→SYN_RECV瞬间→ESTABLISHED。接着在终端 B 按 CtrlC 主动关闭再立刻看会看到FIN_WAIT1→FIN_WAIT2→TIME_WAIT的完整过程。如果服务端先关你会在服务端看到CLOSE_WAIT。# 终端 A起一个只监听不干活的 TCP 服务端 nc -l 9000 # 终端 B连上去 nc 127.0.0.1 9000 # 第三个终端持续观察状态变化 watch -n 0.5 ss -ant | grep 9000逻辑说明nc -l 9000进入 LISTEN终端 B 连接时服务端短暂出现 SYN_RECV握手完成后双方都是 ESTABLISHED。终端 B 断开时作为主动关闭方它会经历 FIN_WAIT1、FIN_WAIT2、TIME_WAIT服务端作为被动关闭方会经历 CLOSE_WAIT直到它自己也调用 close 才发 FIN。参数说明watch -n 0.5每 0.5 秒刷新一次能捕捉到快速变化的状态。ss -ant里-a显示所有状态包括 LISTEN 和非 LISTEN这是关键不加-a会漏掉 LISTEN。能把这套状态变化和三次握手、四次挥手一一对应上说明你对 TCP 连接生命周期的理解已经落地了。我当年就是靠反复跑这个实验才把「CLOSE_WAIT 堆积说明应用没正确关闭连接」这个结论真正记住——后来线上排查连接泄漏第一反应就是去看 CLOSE_WAIT 的数量比翻文档快得多。网络这东西理论背得再熟不动手抓一次包、不看一次状态机遇到问题还是抓瞎。建议你今天就找个空闲机器把上面这几段代码和命令跑一遍比看十篇文章都管用。希望帮到你。本文还有配套的精品资源点击获取
返回列表