目录
[二、5 层网络模型:分层封装与解耦](#二、5 层网络模型:分层封装与解耦)
[四、端口号与 Socket:内核的 "服务标识" 与 "接口"](#四、端口号与 Socket:内核的 “服务标识” 与 “接口”)
本篇文章比较简单,主要概述了网络通信的基本知识。但是我认为重点在于socket套接字与IP:Port:协议号这个三元组的哈希映射表,理解了这个哈希表才能理解网卡是如何把报文精准写到各个socket的缓冲区中,进而通过fd->进程指针,唤醒该进程。
一、通信的本质:跨主机进程间的交互
计算机网络通信,本质上是 "不同主机上的进程之间,进行数据交互" 的过程。
- 跨主机定位 :通过 IP 地址 定位到目标主机。
- 跨进程定位 :通过 端口号(Port) 定位到主机内的具体进程。
- 最终目标:实现进程 P1(本机)与进程 P2(远程服务器)之间的双向通信。


二、5 层网络模型:分层封装与解耦
在OSI中,通常将网络划分成7个层次,但实际中我们会把最顶上的3层(应用层、表示层、会话层)统称为应用层,所以变为5层。网络协议栈是一个分层封装的结构,每一层都为上层提供服务,并添加头部信息。

数据每经过一层,就会添加一层报头信息,一方面可以用来定位;另一方面还可能用来实现可靠传输协议(比如TCP/UDP的超时重传等机制)。可以说:网络协议栈是实现封包、解包的工具。
三、数据发送流程:从应用层到物理层

数据每经过一层,会添加一层头部(Header),并把下层数据作为 "负载数据" 封装。
- 应用层:进程 P1 将业务数据封装成协议包(如 HTTP 请求)。
- 传输层 :添加 TCP/UDP 头 → 关键信息是源端口、目的端口 → 实现 "端到端" 连接。
- 网络层 :添加 IP 头 → 关键信息是源 IP、目的 IP → 实现 "跨主机" 路由。截至目前,报文都在内存中存储、解析、交付。
- 数据链路层 :报文从内存中通过DMA方式拷贝到网卡的缓存中,由网卡外设硬件自动添加数据链路层协议报头。
- 添加 MAC 头(源 MAC / 目的 MAC) → 实现 "局域网内" 设备定位。
- 添加 LLC 头(可选,标识网络层协议) → 说明 "上面是 IP 数据"。
- 末尾添加 FCS (帧校验序列) → CRC32 校验,保证数据传输完整性。
- 物理层:网卡进一步将刚刚封装完成后的报文,编码成二进制信号(ASCII / 二进制),通过网线发出。
四、端口号与 Socket:内核的 "服务标识" 与 "接口"
如果你曾了解过socket套接字相关内容,大概可以知道:Linux中想要使用网络,首先需要创建socket套接字,然后进行bind绑定后才能正常工作。
端口号(Port):
- 网络层抽象:它是内核在网络层面抽象出的 "服务门牌号"。
- 多对多关系:一个端口可对应多个连接(如服务器 80 端口支撑万千请求),多个端口可对应同一个进程(如一个进程监听 8080、9000)。
- 作用:区分同一主机的不同服务,实现权限与逻辑隔离。
Socket(套接字):
- 内核对象 :调用
socket()时,内核创建一个套接字结构,返回一个文件描述符(fd)。- 绑定逻辑 :
bind()将 "进程 + IP + 端口" 绑定到这个 fd。- 分发机制 :当报文到达时,内核通过报文的目标 IP 和端口,快速定位到对应的进程,然后查看该进程的哈希表,检测该报文想发给哪个Socket fd,进而找到对应的进程缓冲区,完成数据交付。
内核最终要做两件事:
1.建立 "端口、IP、协议标记 ↔ socket套接字 " 的映射关系,将数据写入对应缓冲区。
确认数据属于哪个进程(通过 端口 → Socket → 进程),并向进程发送就绪信号,促使进程read。

我最开始理解的是双层哈希:port和进程pid映射,找到进程;再有一个进程内部的fd和port的映射,从而是socket套接字缓冲区可以被正确识别。但经过查阅资料发现:linux内核中仅仅只有IP:Port+协议与socket套接字的哈希映射,至于进程和socket是通过文件系统的指针找到的。
至于为什么不仅仅用Port作为键,是因为现代计算机通常有多个网卡(即多个IP地址),内核无法区分到底是给哪个socket的,而加入IP后就可以区分了,比如192.168.1.0:8080和114.114.114.114:8080就映射了两个完全不同的socket套接字。
而加入协议作为键的原因是:UDP和TCP作为两个独立的协议栈,在UDP中可能已经使用了8080端口,而TCP中同样可以使用8080端口,这并不与我们说的"一个端口只能被一个进程绑定"冲突,因为二者数据完全独立的两个协议栈,就像两个独立的信箱系统,互不干扰。

最后,一般来说:一个进程可以绑定多个端口号,从而监听各种类型数据;但是反过来,一个端口号只能被一个进程绑定(尽管可以让进程多开线程,各线程分别抢数据报文进行处理)。不过现代的高并发技术可能打破这个常规(Nigix等),我还未曾学习过。
