网络模型
同CPU、内存以及I/O一样,网络也是Linux最核心的功能。网络是一种把不同计算机或网络设备连接到一起的技术,它本质上是一种进程间通信方式,主要应用在跨系统的进程间通信,必须要通过网络才能进行。
常见的网络有二层、三层、四层、五层、七层等,那么这些都是指的什么呢?
关于这些层数其实都是国际标准化组织制定的开放式系统互联通信参考模型,简称为OSI网络模型。设定这么多层的原因是因为网络互连异常复杂,需要解决异构设备的兼容性,并解耦复杂的网络包处理流程。
常见的七层网络解释及图示如下:
- 应用层:负责为应用程序提供统一的接口
- 表示层:负责把数据转换成兼容接收系统的格式
- 会话层:负责维护计算机之间的通信连接
- 传输层:负责为数据加上传输表头,形成数据包
- 网络层:负责数据的路由和转发
- 数据链路层:负责MAC寻址、错误侦测和改错
- 物理层:负责在物理网络中传输数据帧
下图来自知乎博主亿图图示:
可以看到,七层网络模型不管是结构还是其中用到的传输协议都异常复杂,所以本博客主要使用的是另一个更实用的四层模型:TCP/IP模型
以下是极客时间倪朋飞老师做的图来对比OSI和TCP/IP模型:
Linux网络栈
有了TCP/IP模型后,在进行数据传输的时候,数据包就会按照协议栈,对上一层发来的数据进行封装处理,然后发给下一层。
封装处理:
每一层都在原来的数据包前面增加固定格式的数据,原来的数据包并不会修改。
比如说下图,传输层就会在应用数据上面添加TCP头,然后将数据传给下一层:
每一层的封装处理都会增加我们这个要发送的网络包的大小。但是,根据协议来看,物理链路所能传输的数据包都是有限制的。一般来说,网络接口配置的最大传输单元(MTU,一般是1500)就规定了最大的IP包大小。
一旦网络包超过了MTU的大小,就会在网络层进行分片,也就是切割这个网络包,分批发送。显然的是,网络包越少,我们要发送的次数就越少,我们的吞吐量也就越大。
Linux网络包的接受流程
当一个网络帧到达网卡之后,网卡会通过DMA(直接存储访问 Direct Memory Access)的方式,把这个网络包放到收包队列中,然后通过硬中断,告诉中断处理程序,我收到了一个网络包,你赶紧来处理。
然后,网卡中断处理程序会为网络帧分配一个内核数据结构(sk_buff),然后将网络包拷贝到这个sk_buff
缓冲区;然后再通过软中断,通知内核处理这个网络帧。
接着,内核会从sk_buff缓冲区中取出这个网络帧,并通过网络栈,逐层处理这个网络包:
- 数据链路层:检查报文合法性,找出上层协议是IPv4还是IPv6,再去掉帧头、帧尾,然后交给网络层
- 网络层:取出ip头,再次判断上层协议是TCP还是UDP,去掉IP头,交给传输层
- 传输层:根据< 源 IP、源端口、目的 IP、目的端口 > 四元组作为标识,找出对应的 Socket,并把数据拷贝到 Socket 的接收缓冲区中。
博主说:
可以看到,光是收到网络包这个流程我们就需要两次拷贝,那么一发一收就是四次拷贝。无疑是很大的性能浪费,感兴趣的同学可以了解一下零拷贝这项技术。
最后,应用程序就可以借助socket接口读取网络包了。
下图是一个网络的接受流程:
至于发送流程,其实就是相反的一个过程:
参考文献
[1] 亿图图示.一文看懂网络七层协议/OSI七层模型.知乎
[2] 倪朋飞.Linux性能优化实战.极客时间