传输层、网络层到底在哪?
很多人学网络分层,最大的问题不是背不住名字。
而是一直不知道:
这些层到底落在哪,到底是什么。
我后来觉得,别先把它想成一堆抽象名词。
如果你一开始根本不知道这些“层”到底是什么,那最容易落地的办法就是:
先粗暴理解成:Linux 发一个包时,内核里一层就是一个函数。
最重要的其实只有三件事:
- 给数据加端口
- 给数据加 IP
- 给数据加 MAC
这三件事想清楚了,网络分层基本就顺了。
一、应用程序一开始只有数据,本身没有端口、IP、MAC
比如你的程序调用:
send(sockfd, buf, len, 0)
这时候你站在应用层视角,手里只有一段业务数据。
比如:
- 一段 HTTP 请求
- 一段 JSON
- 一段文件内容
它本身还不是一个能在网线上跑的包。
它只是:
我要发的内容
后面真正把它一步步变成网络包的,是内核网络栈。
二、传输层先做的事,本质上就是给这段数据加端口
在 Linux 内核里,你可以先粗暴理解成:
传输层就是一个函数。
比如先记:
tcp_sendmsg
这一层最重要的事,不是“把包运到对面机器”。
它先解决的是:
这个数据要交给对方机器上的哪个进程
所以这一层会补上的关键信息就是:
源端口
目标端口
同时 TCP 这一层还会顺手决定:
- 要不要可靠
- 要不要重传
- 顺序怎么保证
但如果只抓最核心的一刀,那就是:
传输层先把“机器里的哪个进程收这个数据”写清楚。
三、网络层再做的事,本质上就是给它加 IP
光有端口还不够。
因为端口只能解决:
到了对方机器以后,交给哪个进程
但它还没回答:
这台对方机器到底在哪里
所以再往下走,会到 IP 这一层。
在 Linux 内核里,你也可以先粗暴理解成:
网络层也是一个函数。
比如先记:
ip_local_out
这一层最重要的动作就是补上:
源 IP
目标 IP
到这里,包才真正带上了:
我要发给哪台机器
所以你可以把网络层理解成:
给这段数据写清楚最终目标机器。
四、链路层再做的事,本质上就是给它加 MAC
很多人最容易卡在这里。
因为一看到 MAC 地址,就会下意识觉得:
既然 IP 是找机器,MAC 也是找机器,那它们是不是一回事?
不是。
IP 解决的是:
最终要去哪台机器
MAC 解决的是:
当前这一跳,先交给谁
在 Linux 内核里,再往下也可以继续这样记:
链路层还是一个函数。
比如先记:
dev_queue_xmit
在真正发出去之前,内核要先决定:
这个包下一跳是谁
如果下一跳是网关,那这一步拿到的就不是“最终远端机器的 MAC”,而是:
网关的 MAC
所以链路层最重要的动作就是:
给当前这一跳补上源 MAC 和目标 MAC。
这也是为什么包每过一台路由器,MAC 地址都可能变。
因为每过一跳,都要重新回答一次:
这一跳先交给谁
但 IP 往往不变,因为最终目标机器没变。
五、这样一看,所谓网络分层,其实就是内核在一路补头
所以整个过程可以先粗暴理解成:
应用数据
-> tcp_sendmsg 加端口
-> ip_local_out 加源 IP/目标 IP
-> dev_queue_xmit 加源 MAC/目标 MAC
-> 网卡把它发出去
如果你非要把它翻译成“每层到底解决什么问题”,那就是:
- 应用层:我要发什么
- 传输层:发给对方机器上的哪个进程
- 网络层:目标机器在哪里
- 链路层:当前这一跳交给谁
所以网络分层不是为了背名字。
而是因为一次发包,本来就要补三种完全不同的信息:
- 端口
- IP
- MAC
这三种信息不一样,所以才拆成三层。
最后一句
很多人学网络分层看不懂,不是因为层名难背,而是没把它和内核真实发包过程连起来。站在 Linux 网络栈里看,最核心的事其实很简单:应用先给数据,传输层加端口,网络层加 IP,链路层加 MAC,然后网卡再把它真正发出去。