33-基础篇:关于Linux网络,你必须知道这些(上)





同CPU、内存以及I/O一样,网络也是Linux系统最核心的功能
网络是一种把不同计算机或网络设备连接到一起的技术
它本质上是一种进程间通信方式,特别是跨系统的进程间通信,必须要通过网络才能进行
随着高并发、分布式、云计算、微服务等技术的普及,网络的性能也变得越来越重要


网络模型

OSI网络模型,开放式系统互联通信参考模型

为了解决网络互联中异构设备的兼容性问题,并解耦复杂的网络包处理流程
OSI模型把网络互联的框架分为应用层、表示层、会话层、传输层、网络层、数据链路层以及物理层等七层
每个层负责不同的功能

  1. 应用层,负责为应用程序提供统一的接口
  2. 表示层,负责把数据转换成兼容接收系统的格式
  3. 会话层,负责维护计算机之间的通信连接
  4. 传输层,负责为数据加上传输表头,形成数据包
  5. 网络层,负责数据的路由和转发
  6. 数据链路层,负责MAC寻址、错误侦测和改错
  7. 物理层,负责在物理网络中传输数据帧

但是OSI模型还是太复杂了,也没能提供一个可实现的方法
所以在Linux中,实际上使用的是另一个更实用的四层模型,即TCP/IP网络模型

TCP/IP模型,把网络互联的框架分为应用层、传输层、网络层、网络接口层等四层

  1. 应用层,负责向用户提供一组应用程序,比如HTTP、FTP、DNS等
  2. 传输层,负责端到端的通信,比如TCP、UDP等
  3. 网络层,负责网络包的封装、寻址和路由,比如IP、ICMP等
  4. 网络接口层,负责网络包在物理网络中的传输,比如MAC寻址、错误侦测以及通过网 卡传输网络帧等

TCP/IP与OSI模型的关系图

image-20211224151003880

当然了,虽说Linux实际按照TCP/IP模型,实现了网络协议栈
但在平时的学习交流中,习惯上还是用OSI七层模型来描述
比如,说到七层和四层负载均衡,对应的分别是OSI模型中的应用层和传输层
(而对应到TCP/IP模型中,实际上是四层和三层)




Linux网络栈

有了TCP/IP模型后,在进行网络传输时,数据包就会按照协议栈,对上一层发来的数据进行逐层处理
然后封装上该层的协议头,再发送给下一层

当然网络包在每一层的处理逻辑,都取决于各层采用的网络协议
比如在应用层,一个提供REST API的应用
可以使用HTTP协议,把它需要传输的JSON数据封装到HTTP协议中,然后向下传递给TCP层

而封装做的事情就很简单了,只是在原来的负载前后,增加固定格式的元数据,原始的负载数据并不会被修改

比如,以通过TCP协议通信的网络包为例
通过下面这张图可以看到,应用程序数据在每个层的封装格式
image-20211224152743009

  1. 传输层在应用程序数据前面增加了TCP头
  2. 网络层在TCP数据包前增加了IP头
  3. 网络接口层,又在IP数据包前后分别增加了帧头和帧尾

这些新增的头部和尾部,增加了网络包的大小
物理链路中并不能传输任意大小的数据包
网络接口配置的最大传输单元(MTU),就规定了最大的IP包大小
在最常用的以太网中,MTU默认值是1500(这也是Linux的默认值)
一旦网络包超过MTU的大小,就会在网络层分片,以保证分片后的IP包不大于MTU值
显然,MTU越大,需要的分包也就越少,自然,网络吞吐能力就越好

理解了TCP/IP网络模型和网络包的封装原理后
很容易能想到Linux内核中的网络栈,其实也类似于 CP/IP的四层结构
如下图所示,就是Linux通用IP网络栈的示意图

image-20211224153003626

  1. 最上层的应用程序,需要通过系统调用,来跟套接字接口进行交互
  2. 套接字的下面,就是前面提到的传输层、网络层和网络接口层
  3. 最底层,则是网卡驱动程序以及物理网卡设备

网卡是发送和接收网络包的基本设备
在系统启动过程中,网卡通过内核中的网卡驱动程序注册到系统中
而在网络收发过程中,内核通过中断跟网卡进行交互

再结合前面提到的Linux网络栈,可以看出,网络包的处理非常复杂
所以,网卡硬中断只处理最核心的网卡数据读取或发送,而协议栈中的大部分逻辑,都会放到软中断中处理




Linux网络收发流程

了解了Linux网络栈后,再来看看Linux到底是怎么收发网络包的

注意以下内容都以物理网卡为例
事实上Linux 还支持众多的虚拟网络设备,而它们的网络收发流程会有一些差别



网络包的接收流程

  1. 当一个网络帧到达网卡后,网卡会通过DMA方式,把这个网络包放到收包队列中
    然后通过硬中断,告诉中断处理程序已经收到了网络包

  2. 接着,网卡中断处理程序会为网络帧分配内核数据结构(sk_buff),并将其拷贝到sk_buff缓冲区中
    然后再通过软中断,通知内核收到了新的网络帧

  3. 接下来,内核协议栈从缓冲区中取出网络帧,并通过网络协议栈,从下到上逐层处理这个网络帧

    1. 在链路层检查报文的合法性,找出上层协议的类型(比如IPv4还是IPv6)
      再去掉帧 头、帧尾,然后交给网络层
    2. 网络层取出IP头,判断网络包下一步的走向,比如是交给上层处理还是转发
      当网络层确认这个包是要发送到本机后,就会取出上层协议的类型(比如TCP还是UDP)
      去掉IP头,再交给传输层处理
    3. 传输层取出TCP头或者UDP头后,根据 <源IP、源端口、目的IP、目的端口> 四元组作为标识
      找出对应的Socket,并把数据拷贝到Socket的接收缓存中
    4. 最后应用程序就可以使用Socket接口,读取到新接收到的数据了

为了更清晰表示这个流程,这张图的左半部分表示接收流程,而图中的粉色箭头则表示网络包的处理路径

image-20211224153420420



网络包的发送流程

了解网络包的接收流程后,就很容易理解网络包的发送流程
网络包的发送流程就是上图 的右半部分,很容易发现,网络包的发送方向,正好跟接收方向相反

  1. 首先,应用程序调用Socket API(比如 sendmsg)发送网络包

  2. 由于这是一个系统调用,所以会陷入到内核态的套接字层中
    套接字层会把数据包放到 Socket 发送缓冲区中

  3. 接下来,网络协议栈从Socket发送缓冲区中,取出数据包
    再按照TCP/IP栈,从上到下逐层处理
    比如,传输层和网络层,分别为其增加TCP头和IP头,执行路由查找确认下一跳的IP,并按照MTU大小进行分片

  4. 分片后的网络包,再送到网络接口层,进行物理地址寻址,以找到下一跳的MAC地址
    然后添加帧头和帧尾,放到发包队列中
    这一切完成后,会有软中断通知驱动程序,发包队列中有新的网络帧需要发送

  5. 最后,驱动程序通过DMA ,从发包队列中读出网络帧,并通过物理网卡把它发送出去




小结

Linux网络的工作原理

  1. 多台服务器通过网卡、交换机、路由器等网络设备连接到一起,构成了相互连接的网络
    由于网络设备的异构性和网络协议的复杂性,国际标准化组织定义了一个七层的OSI网络模型,
    但是这个模型过于复杂,实际工作中的事实标准,是更为实用的TCP/IP模型
  2. TCP/IP模型,把网络互联的框架,分为应用层、传输层、网络层、网络接口层等四层,
    这也是Linux网络栈最核心的构成部分
    1. 应用程序通过套接字接口发送数据包,先要在网络协议栈中从上到下进行逐层处理,最终再送到网卡发送出去
    2. 接收时,同样先经过网络栈从下到上的逐层处理,最终才会送到应用程序

posted @ 2021-12-24 15:42  李成果  阅读(129)  评论(0编辑  收藏  举报