传输层、网络层到底在哪?

7 阅读4分钟

传输层、网络层到底在哪?

很多人学网络分层,最大的问题不是背不住名字。

而是一直不知道:

这些层到底落在哪,到底是什么。

我后来觉得,别先把它想成一堆抽象名词。

如果你一开始根本不知道这些“层”到底是什么,那最容易落地的办法就是:

先粗暴理解成: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,然后网卡再把它真正发出去。