1. 从“发包裹”说起:TCP/IP协议到底是什么
我先抛个问题:你有没有想过,当你在浏览器里敲下域名、按下回车,到页面刷出来,这中间到底发生了什么?如果有一天面试官这么问你,你怎么回答?
答案就藏在一个词里——TCP/IP协议。它不是单个协议,而是一整套“网络通信规则”。你可以把它理解成快递行业的整套运作流程:你写了收货地址(IP),填了寄件人(源IP),快递员按地址跑腿(路由),快递面单上还得有“收件人姓名”(端口),如果东西贵重还得保价、签收确认(TCP),如果只是普通小件丢了也不心疼,那就发普通快递(UDP)。这套规则从头到尾规定了“怎么包装、怎么填单、怎么跑线路、怎么验货”,缺一环,你的数据就送不到对的地方。
这篇文章是写给谁的?给所有被“TCP/IP”这四个字劝退过的同学。不管你是刚入行的后端开发、运维小白、网工实习生,还是产品经理想搞懂点底层逻辑,都能看。我会用“寄快递”“打电话”这类生活类比,把四层模型、IP地址、端口、三次握手、四次挥手这些看似高大上的东西拆开揉碎,最后还会带上我在实际抓包、排障时踩过的坑。保证你读完不是“好像懂了”,而是真能上手排查问题。
2. 先把骨架搭起来:TCP/IP四层模型到底分了啥
2.1 为什么非要分层,不分行不行
早年网络设备百花齐放,各家有各家的协议,不同厂商的设备之间根本没法互通,就像电话刚发明时,不同公司的电话网接不到一块。为了解决这个问题,业界定了一套公共规范,让“会说人话”的设备都能互相通信。
分层的核心思路是:每个人只管自己那一层的活儿,上层不关心下层怎么实现,下层也不理解上层在说什么。就好比快递小哥不用懂你的电脑是怎么把网页生成出来的,他只管送包裹;而你寄快递也不用懂卡车怎么走高速,你只需要填单子。
TCP/IP模型常被简化成四层:
| 层级 | 名字 | 职责 | 你熟悉的东西 |
|---|---|---|---|
| 第4层 | 应用层 | 生成数据,面向用户 | HTTP、DNS、FTP、SSH |
| 第3层 | 传输层 | 端到端的可靠传输或尽力传输 | TCP、UDP |
| 第2层 | 网际层 | 寻址与路由,找到目标主机 | IP、ICMP、ARP |
| 第1层 | 网络接口层 | 物理传输,比特流转成电信号/光信号 | 以太网帧、WiFi |
注意,TCP/IP模型是事实上的工业标准,而OSI七层是理论上的教学模型。考试归考试,工作中你只用记住这四层就够了。
2.2 每一层到底干了什么事
拿你打开百度首页举例,一个数据包的“旅行”过程是这样的:
- 应用层:浏览器生成一个HTTP请求,要获取baidu.com的主页内容。
- 传输层:TCP把这段请求切成合适大小的“数据段”,给它编号,保证顺序,还要建立可靠的连接信道。
- 网际层:IP协议在数据段外面套上IP头,写上源IP和目的IP,相当于写了寄件地址和收件地址。
- 网络接口层:再封装成帧,通过网卡变成光信号/电信号,走物理线路出去。
到了百度服务器那边,顺序反过来:物理层收到信号,剥开帧,剥开IP头,剥开TCP头,最后把HTTP请求交给百度后端的程序处理。每一层只处理自己关心的头部信息,然后把剩下的“包裹”往上传——这就是“分层”最优雅的地方:各层独立演进,互不干扰。
2.3 为什么OSI七层模型反而没统一世界
你可能听过OSI七层模型,它把网络分成七层,看起来更严谨,为什么实际用的是TCP/IP呢?原因很现实:OSI太完美,落地太慢;TCP/IP先实用主义地跑起来了,而且逐层开放、免费、代码开源,Linux和Unix生态全站TCP/IP。等OSI标准磨磨蹭蹭定稿时,世界已经被TCP/IP占领了。所以你现在看到的互联网,骨子里跑的是TCP/IP这套简洁的分层方案。
3. 核心主角:IP地址、端口、MAC地址到底在干嘛
3.1 IP地址就是“门牌号”,但它是有版本的
IPv4是32位,约43亿个地址,长这样:192.168.1.1。今天早就不够用了。IPv6是128位,数量多到可以给地球上的每一粒沙子分配地址。普通用户见到最多的是IPv4,但服务器、云主机、运营商网络都在悄悄往IPv6迁移。
IPv4地址还分公网IP和内网IP。你家路由器后面的设备,全是内网IP,比如192.168.x.x、10.x.x.x、172.16.x.x。这些地址在外面路由上不可路由,靠路由器做NAT(网络地址转换)才能上网。这就是为什么你家里的电脑没法被外网直接访问——因为外网根本不知道你这个内网IP是谁。
3.2 端口:光有IP还不够,你得说清楚找“哪个人”
假设IP是公司地址,那端口就是部门分机号。你访问一台服务器的80端口跑的是Web服务,22端口跑的是SSH服务,3306是MySQL。IP + 端口组合(比如 192.168.1.10:8080),才能精确定位到一台机器上的一个具体应用。
端口分为著名的0-1023(需要特权,如80、443)、注册端口1024-49151、动态/私有端口49152-65535。客户端发起请求时,会随机从高位端口选一个出厂,跟服务器通信。所以你在服务端日志里看到的“源端口”,经常是那种稀奇古怪的四位数。
3.3 MAC地址:快递到了小区门口,还得靠门牌找具体楼层
IP负责跨网络寻址,MAC地址负责“最后一跳”。网络包一层层转发时,到达本地网络,要用ARP协议把“目标IP”翻译成“目标MAC地址”,然后帧才能在以太网里播出。网上找IP,本地靠MAC,是这个体系里特别容易混淆的一点。
注意:IP地址是逻辑的、可以变的;MAC地址是物理的、出厂烧录的。换了一台电脑,同一个IP会有不同的MAC,永远不要用MAC当业务标识。
4. 传输层两大护法:TCP和UDP的相爱相杀
4.1 TCP:面向连接,可靠,像打电话
TCP能保证数据不丢、不乱序、不重复,靠的是三个机制:握手建立连接、序列号管理、确认重传。
我讲讲经典三次握手(SYN、SYN-ACK、ACK):
- 客户端发送SYN(同步序列号)报文,携带初始序列号X,告诉服务器“我要连你”。
- 服务器回复SYN-ACK,携带自己的初始序列号Y,同时确认收到了X(ACK=X+1)。
- 客户端再回一个ACK,确认收到Y。此时双方连接建立。
为什么是三次不是两次?因为双方都得确认“我能发数据你能收到、你能发数据我能收到”。两次握手只能保证“客户端确认服务器能听”,服务器那边不知道自己的回复客户端有没有收到,容易造成半连接和资源浪费。
4.2 四次挥手:再见为什么要挥四次
断开连接时,要四次挥手(FIN、ACK、FIN、ACK):
- 主动关闭方(比如客户端)发FIN,表示“我没有数据发了”。
- 被动方回ACK,表示“我知道了”。但此时被动方可能还有数据没发完,所以连接还没断。
- 被动方数据发完后,发FIN,表示“我这边也没数据了”。
- 主动方回ACK,之后等待2MSL才完全关闭。
FIN和ACK分开成两步,是四次而不是三次的根本原因——TCP是双工通道,两个方向需要各自独立地关闭。
2MSL等待是个坑:如果主动方直接关闭,最后那个ACK丢了,被动方会一直重发FIN,浪费资源。等待2MSL能保证最后的ACK足够到达对端,同时也能让旧连接上的延迟包在网络里消亡,不至于污染新连接。
4.3 UDP:无连接,尽力而为,像寄明信片
UDP没有握手、没有确认、没有重传,直接“写地址、投递”。好处是开销小、延迟低;坏处是丢包了对方不知道。语音通话、视频直播、DNS查询、游戏帧同步都用UDP,因为实时性比可靠性重要。游戏里少一帧画面可以接受,但如果画面为了“等重传”卡住,体验直接爆炸。
4.4 TCP vs UDP 怎么选,一张表说明白
| 对比项 | TCP | UDP |
|---|---|---|
| 连接状态 | 有连接 | 无连接 |
| 可靠性 | 可靠,有序 | 尽力而为,无序 |
| 传输效率 | 低一点点 | 高 |
| 应用场景 | HTTP、FTP、邮件、数据库 | 直播、游戏、DNS、物联网上报 |
| 拥塞控制 | 有 | 无 |
实际工程里还有个“中间态”:UDP上叠加QUIC。QUIC是在UDP之上实现可靠传输+加密,快并且可靠,新一代HTTP/3就基于QUIC。这说明TCP和UDP不是非黑即白,工程上完全可以自己叠加协议。
5. 应用层的幕后功臣:DNS和HTTP的配合
5.1 DNS:把baidu.com翻译成IP的“电话簿”
人记域名,机器记IP。DNS就是一个全球分布式电话簿。你输入www.baidu.com后,本地DNS服务器会一层层去问:根DNS、顶级域DNS、权威DNS,拿到IP后才开始真正的HTTP请求。这过程叫“递归查询”和“迭代查询”。
DNS是UDP 53端口,但区域传输用TCP 53;响应如果太大,也会切到TCP。我之前排查过一个“网页加载偶尔超时”的故障,查了半天发现是本地DNS的UDP响应被防火墙丢包,改用TCP后就好了。DNS不总是UDP,很多人在这栽过跟头。
5.2 HTTP与HTTPS:协议栈的“最终输出”
HTTP跑在TCP上,默认80端口;HTTPS跑在TCP上但外面套了TLS,默认443端口。你看到的网页请求,本质上是:
HTTP请求 TCP数据段 IP数据报 以太网帧四层各加一个头,逐层封装。用抓包工具看就是一个“洋葱”,从最底下物理帧一路剥开,最后露出HTTP的内容。
5.3 你随时随地都在用TCP/IP但没感觉到
手机看视频、聊天软件发消息、扫码付款、远程打卡……每天高频使用的App,底层全是TCP/IP协议栈。没有这套协议,互联网设备就是一座座信息孤岛。理解了协议栈,你再学什么Nginx、Docker网络、K8s Service,会发现全是TCP/IP的延伸——K8s的Service就是基于IPVS/iptables做转发,本质还是IP+端口那套逻辑。
6. 实战:5分钟排查一次网络故障的完整思路
6.1 故障排查的第一步,不是重启路由器,而是分层定位
我用这套思路解决过无数次线上问题。拿到“上不了网”的反馈,按顺序排查:
- 先看网卡状态:
ip addr,有没有拿到IP地址,接口是否UP。 - 看网关通不通:
ping 网关IP。通了,说明本机到路由器没问题。 - 看外网通不通:
ping 8.8.8.8或ping 223.5.5.5。通了,说明路由和物理链路正常。 - 看DNS解析正不正常:
nslookup baidu.com,解析出IP,说明DNS没问题。 - 如果是某个端口不通:用
telnet ip 端口或nc -vz ip 端口测试。
这套“从底层往上ping,从上层往下查”的思路,比瞎猜高效百倍。
6.2 常用命令,人人都会用但不一定用明白
ping:验证三层连通性 + 最基本的路由质量。注意ping通不代表端口通,端口是四层的事。traceroute(Linux)/tracert(Windows):看数据包经过哪些路由节点。哪一跳延迟高,故障点基本就在那附近。ss -tunlp/netstat -tunlp:本机监听端口和连接状态。tcpdump:抓包利器。比如抓80端口的包:tcpdump -i eth0 tcp port 80 -nn -c 100。dig/nslookup:DNS查询,适合排查解析问题。
6.3 用tcpdump现场抓一次三次握手
为了方便演示,我假设你要访问example.com。开两个终端:
终端1:
sudo tcpdump -i eth0 tcp port 80 -nn终端2:
curl http://example.com正常情况下你会看到:
IP 你本机IP.随机端口 > 目标IP.80: Flags [S] IP 目标IP.80 > 你本机IP.随机端口: Flags [S.] IP 你本机IP.随机端口 > 目标IP.80: Flags [.]S是SYN,S.是SYN-ACK,.是纯ACK。看到这3条,说明三次握手完成了。如果只看到第一条SYN,没有后续响应,说明目标端口被防火墙拦了,或者服务根本没启动。这个技巧我在线上排查时用了无数次,比看日志直观多了。
6.4 常见协议状态速查
ss -ant输出里的TCP状态,字段含义要心里有数:
| 状态 | 含义 | 常见原因 |
|---|---|---|
| LISTEN | 服务在监听端口 | 正常 |
| ESTABLISHED | 连接已建立 | 正常,通信中 |
| SYN_SENT | 发出SYN,未收到回包 | 目标不可达、防火墙丢包 |
| SYN_RECV | 收到SYN,未完成握手 | 半连接队列满、服务过载 |
| TIME_WAIT | 主动关闭方等待2MSL | 正常,但量大要调参 |
| CLOSE_WAIT | 被动方等待应用关闭连接 | 代码没关socket,非常经典的故障 |
我在线上见过大量CLOSE_WAIT堆积的场景,一般是服务端代码没有正确关闭连接导致的,排查方向就是看程序有没有释放socket资源。
7. 工作中最容易踩的TCP/IP坑
7.1 内网IP不够用?网段划分记住这几个
- 192.168.0.0/16:最常见的家庭网络。
- 10.0.0.0/8:大企业、云VPC常用。
- 172.16.0.0/12:老网络里偶尔见。
子网掩码决定一个网段里有多少可用主机。比如192.168.1.0/24,前24位是网络号,后8位是主机号,可用主机最多254台。规划VPC时记住先确定掩码,再定网段,不要随手写个/24然后发现机器不够用。
7.2 网关、路由、NAT,搞混必出事
网关是出口,路由是“下一跳”的决策逻辑,NAT是地址转换。家里网关一般是路由器内网IP,云上VPC网关一般是网络入口节点。路由表则决定这个包朝哪个方向走:
ip route show如果路由表异常,或者默认路由丢了,网络就直接断了。我在K8s集群里见过很多节点网络异常,排查第一步永远是:
ip route | grep default默认路由没了,容器网络再花哨也白搭。
7.3 IPv6来了,你的服务还只监听IPv4吗
现在很多云服务默认打开IPv6,但你的Nginx或Java服务可能只监听IPv4的0.0.0.0:80,导致IPv6地址访问不通。排查方法:
ss -tlnp | grep :80如果监听的地址是::ffff:0.0.0.0:80,说明双栈兼容;如果只有0.0.0.0:80,IPv6访问就会被拒。解决办法通常是同时监听IPv6的[::]:80。
7.4 TCP缓冲区、MTU问题,像隐形炸弹
TCP有个机制叫滑动窗口+缓冲区,发送方和接收方都有固定大小的缓存区。如果缓冲区设置太小,大文件传输效率就很低。而MTU(最大传输单元)通常为1500字节,如果你的机器和路由器MTU不一致,就会出现“能上QQ但打不开网页”的诡异现象,往往是分片被丢或者DF位导致的问题。
遇到这种问题,按这个思路调:
ifconfig eth0 mtu 1400临时改小MTU测试,如果正常,就是MTU不一致,再把路由器MTU调成一致即可。
8. TCP/IP学会后,下一步该往哪走
TCP/IP是网络世界的“底层方言”,但光懂协议不会用,学习效果打五折。建议照着做一遍:
- 在本机抓一次访问某个网站的完整包,对照本文看TCP握手、HTTP请求、TCP挥手。
- 搭一个最简单的Python HTTP服务器,用tcpdump观察它和浏览器的通信过程。
- 学会看
ss -ant状态,模拟断网、防火墙规则,观察状态怎么变化。 - 手动配一次静态IP、网关、DNS,强迫自己理解三层要素。
如果把这套流程走完,你已经比很多工作两三年的开发更懂网络了。下一阶段可以学Nginx反向代理、负载均衡、Docker网络模型、K8s Service,本质上都是TCP/IP的“业务编排”。
最后再分享一个小技巧:排查网络问题的时候,心里永远装着“分层”这两个字,从物理到应用一层层排除,效率会翻倍。我见过太多人一上来就重启、重装、清缓存,结果问题出在一台设备MTU不对上。TCP/IP这玩意儿值钱的地方不在于背概念,在于出问题的时候,你能看着数据包叙述完整的故事。