Linux 收发网络包的流程

news/2024/4/26 16:56:39/文章来源:https://blog.csdn.net/2301_79516932/article/details/137108107
  1. 应用层:

    • 功能:提供应用程序间通信。
    • 例子:电子邮件客户端如Outlook或Thunderbird,它们提供用户界面来发送和接收电子邮件。这些客户端使用SMTP(用于发送邮件)和IMAP或POP3(用于接收邮件)这样的应用层协议。
  2. 表示层:

    • 功能:确保信息的语义在不同系统间传输时保持不变,通常涉及数据格式转换。
    • 例子:当一个Web服务将数据从一种格式(如数据库中的二进制数据)转换为另一种格式(如JSON或XML)以供Web客户端使用时,就是表示层在起作用。
  3. 会话层:

    • 功能:建立、管理和终止应用程序之间的会话。
    • 例子:在网银交易中,当用户登录到他们的账户进行操作时,会话层负责维护和管理这个会话的完整性和安全性,例如RPC。
  4. 传输层:

    • 功能:实现端到端的数据传输。
    • 例子:TCP(传输控制协议)确保数据包的正确顺序传输,比如在一个网页请求中从服务器传送HTML文件到你的浏览器。
  5. 网络层:

    • 功能:负责数据的路由选择和传输。
    • 例子:当你在浏览器中输入一个网址时,IP协议(网络层的一部分)帮助确定数据包应该如何从你的设备路由到目标服务器。
  6. 数据链路层:

    • 功能:确保在同一网络中或两个直接连接的网络设备间的可靠数据传输。
    • 例子:以太网(Ethernet)是数据链路层的一个实例,它通过MAC地址对网络中的设备进行识别和通信。
  7. 物理层:

    • 功能:在物理媒介上传输原始比特流。
    • 例子:双绞线、光纤或无线电波等传输媒介,在这些媒介上,物理层以电信号、光脉冲或无线信号的形式传输数据。

Linux 接收网络包的流程

网卡是计算机里的一个硬件,专门负责接收和发送网络包,当网卡接收到一个网络包后,会通过 DMA 技术,将网络包写入到指定的内存地址,也就是写入到 Ring Buffer ,这个是一个环形缓冲区,接着就会告诉操作系统这个网络包已经到达。

DMA(Direct Memory Access)是一种允许某些硬件子系统直接访问主内存的技术,用于数据传输。当网卡接收到一个网络包后,使用DMA技术可以直接将网络包写入到计算机内存的指定地址,而不需要CPU的介入,这样可以显著提高数据传输的效率。

DMA的工作原理如下:

  1. 硬件配置: 网卡(或其他DMA支持的硬件设备)被配置为对特定内存地址有直接访问的权限。
  2. 接收数据: 当网卡接收到数据(如网络包)时,它会启动DMA传输。
  3. 内存写入: DMA控制器接管数据传输任务,直接将数据从网卡传输到预定的内存地址,无需CPU参与。这意味着CPU可以同时处理其他任务,而不必被数据传输过程所占用。
  4. 中断信号: 数据传输完成后,DMA控制器会发送一个中断信号给CPU,告知它数据已经被成功传输并存储在内存中。

通过这种方式,DMA提高了数据处理的效率,尤其是在处理大量数据或高速数据流时。它是现代计算机和网络设备中不可或缺的一部分,用于优化数据传输过程,减轻CPU的负担。

如何知道网络包到了

每当网卡收到了一个网络包,就会触发一个硬中断,告诉操作系统要去拿数据咯。

但是这就会有一个致命的问题,因为网卡触发的是硬中断,优先级很高,如果这时候有很多很多的网络包发送过来,那岂不是得一直硬中断了,那还怎么处理其他的进程呢?

因此,为了解决频繁中断带来的性能开销,Linux 内核在 2.6 版本中引入了 NAPI 机制

NAPI(New API)机制是为了改进Linux内核处理网络数据包的方式,特别是在高速网络环境下。传统的网络数据包处理机制是完全中断驱动的:每收到一个数据包就产生一个硬中断,这在数据包到达速率非常高的时候会导致大量的CPU中断,从而影响系统性能。

NAPI的目标是通过引入轮询机制来减少在高负载下处理网络数据包时的中断数量。NAPI机制工作的基本流程如下:

  1. 正常模式: 当网络负载较低时,系统使用传统的中断驱动机制。网卡接收到数据包时会产生中断,由中断处理函数(Interrupt Service Routine, ISR)来处理。
  2. 高负载检测: 当网卡开始接收到大量的数据包时,ISR会判断是否需要转为NAPI模式。这通常基于接收到数据包的速率。
  3. NAPI模式: 在NAPI模式下,硬中断会被禁用,ISR会将网卡设置到一个轮询模式。在轮询模式中,不是对每个接收到的数据包产生硬中断,而是在网络驱动的轮询函数中处理多个数据包。
  4. 轮询函数处理: 内核会定期调用网卡驱动的轮询函数(也称为poll函数),该函数负责批量处理接收到的数据包。处理过程中,如果数据包到达速率降低,或者已经处理了足够多的数据包,轮询函数会重新启用硬中断并退出NAPI模式。

例子:

假设你有一个网卡支持10Gb/s的速率,当网络流量低时,每个数据包的到达会触发一个硬中断,由CPU处理。这在低流量下是可行的。

然而,在一个高流量场景下,比如服务器正在处理成千上万的并发连接,或者正在进行大规模数据传输,这时每个数据包都触发中断就会导致CPU花费大量时间去处理中断本身,而不是数据包。在这种情况下,启用NAPI模式可以显著减少中断的数量,网卡驱动会在轮询函数中一次处理多个数据包,减轻了CPU的负担,提高了系统的整体性能。

也就是说,正常情况下还是通过硬中断的方式去处理网络包,当请求较大的时候会开启NAPI模式,提升整体性能。

在Linux内核当中有一个ksoftirqd线程是专门来处理负载很重的软中断的。

  1. 网络包接收: 当网卡接收到网络数据包,它们首先被放入到网卡的接收环形缓冲区(Ring Buffer)中。
  2. 触发软中断: 一旦环形缓冲区中有数据包,网卡会触发一个软中断(或者在高流量情况下由硬中断切换到轮询模式后,通过轮询来处理)。这个软中断是通过内核的软中断系统(softirq)来处理的,而不是传统的硬中断处理方式。
  3. ksoftirqd处理: 如果软中断的处理负载很重,可能会唤醒专门的内核线程ksoftirqd来处理。这个内核线程会从接收环形缓冲区中取出数据包,并封装成sk_buff结构体。
  4. 交付协议栈: 一旦数据包被封装到sk_buff,它就会被交付到网络协议栈进行进一步处理。这包括从数据链路层到网络层,然后到传输层,最终可能到应用层。
  5. 逐层处理: 在协议栈的每一层,sk_buff会被相应的层处理。例如,在网络层,IP头部会被解析,并根据需要进行路由。在传输层,TCP或UDP头部会被处理,并且数据会被传递到相应的socket缓冲区。

总结

  1. 网络接口层(数据链路层):
    • 数据包首先到达网络接口,并被放置在环形缓冲区(Ring Buffer)中。
    • 当环形缓冲区接收到数据后,会触发一个软中断(或者在某些情况下是NAPI轮询机制)。
    • ksoftirqd内核线程(或者在高负载时直接由中断上下文)处理这些软中断,从环形缓冲区中取出数据帧。
    • 使用sk_buff结构来表示网络包,并进行基本的合法性检查,如CRC检验等,不合法的帧会被丢弃。
    • 识别上层协议(如IPv4, IPv6),并移除数据链路层的头(如以太网帧头)。
  2. 网络层:
    • 在网络层,包括IP头的网络数据包会被进一步处理。
    • 内核检查IP包的目的地址,决定是将数据包传递给上层协议还是路由转发。
    • 对于本机处理的包,内核检查IP头部确定上层协议(如TCP或UDP),并移除IP头。
  3. 传输层:
    • 在传输层,TCP或UDP头被处理。
    • 根据源IP地址、源端口、目的IP地址和目的端口四元组标识找到对应的套接字(Socket)。
    • 数据被放入相应Socket的接收缓冲区。
  4. 应用层:
    • 应用程序通过系统调用(如readrecvfrom),请求从套接字缓冲区读取数据。
    • 数据从内核空间的Socket接收缓冲区复制到用户空间的应用层缓冲区。
    • 应用程序继续处理接收到的数据。

在这个过程中,内核对网络数据包的处理是分层的,并且每层只处理对应层次的协议头和数据。利用sk_buff来在各层之间传递数据包可以实现有效的数据处理,因为它避免了不必要的数据复制,从而提高了性能。

Linux 发送网络包的流程

  1. 系统调用: 应用程序调用Socket API来发送数据。这会触发从用户态到内核态的切换。
  2. 内存分配: 内核为要发送的数据分配sk_buff结构体。用户空间的数据被复制到这个新分配的sk_buff中。
  3. 发送缓冲区: sk_buff被加入到Socket关联的发送缓冲区中。
  4. TCP协议处理: 如果使用TCP,因为 sk_buff 后续在调用网络层,最后到达网卡发送完成的时候,这个 sk_buff会被释放掉。而 TCP 协议是支持丢失重传的,在收到对方的 ACK 之前,这个 sk_buff 不能被删除,sk_buff的副本会在传输层(TCP、UDP)被创建。
  5. 协议封装: sk_buff随后经历协议栈各层的处理,每一层添加它自己的头信息。对于TCP,会添加TCP头;对于IP层,添加IP头;在数据链路层,会添加如以太网帧头。
  6. 头部空间:sk_buff中,head指针指向缓冲区的起始位置,data指针指向当前层数据的起始位置。通过调整data指针,可以在headdata之间预留空间,用于填充协议头。
  7. 数据传输: 一旦协议封装完成,数据包(sk_buff)就被发送到网络接口层,准备通过物理硬件发送出去。
  • 在TCP协议封装之后,传输层将检查sk_buff中的数据量是否超过了MSS大小。
  • 如果数据量超过MSS,TCP层会将数据分为几个段,每个段的大小不会超过MSS。这是为了确保每个TCP段在加上TCP头之后形成的IP数据包,加上IP头之后仍然不会超过MTU的大小,避免在IP层进行分片。
  • 这些分段后的数据会被封装在各自的sk_buff中,并加上TCP头。

在接收数据包的过程中,sk_buff中的data指针会向后移动(增加),以剥离协议头部,而在发送数据包的过程中,data指针会向前移动(减少),为协议头预留空间。这种处理方式允许在不同的网络层之间传递数据包时避免不必要的数据拷贝,优化了CPU的使用效率。

(a) 空的sk_buff结构体: 初始化状态,没有数据。

(b) 分配内存:sk_buff的缓冲区中分配了足够的内存,这包括headdatatailend指针,为添加协议头部留出了空间。此时datatail指向相同的位置,表示还没有添加任何数据。

© 添加L1层数据(比如MAC层或物理层头部):data指针之前添加了L1层的头部信息。此时data指针向下移动,指向L1头部的开始。len表示sk_buff中总的数据长度。

(d) 添加L2层数据(比如TCP头部): 在L1层头部之前进一步添加了L2层的头部(例如TCP头部)。data指针继续上移,len增加。

(e) 添加L3层数据(比如IP头部): 接着添加了L3层的头部(例如IP头部),data指针继续上移,len再次增加。

(f) 添加L4层数据(比如以太网头部): 最后,添加了L4层的头部信息(例如以太网头部),完成了数据包的封装过程。data指针现在指向整个封装好的数据包的起始位置,len为整个数据包的长度。

在发送数据包的过程中,每次添加新的协议头部,都会调整sk_buff中的data指针,将其向上移动到新的头部的开始位置,同时更新len来反映新的总长度。这样,就可以在不进行数据拷贝的情况下,动态地构建网络数据包。

上面就是传输层的过程的,接下来就是网络层。

  1. 网络层处理:
    • 网络层选择路由(下一跳IP),填充IP头,执行netfilter过滤。
    • 如果数据包超过MTU,进行IP层的分片。
    • 分片后的数据包仍然封装在sk_buff结构体中。
  2. 网络接口层:
    • 通过ARP协议获取下一跳的MAC地址。
    • 填充数据链路层的帧头和帧尾到sk_buff
    • sk_buff放入网卡的发送队列。
  3. 硬件处理:
    • 触发软中断,通知网卡驱动有新的数据包待发送。
    • 网卡驱动从发送队列读取sk_buff,将其数据映射到网卡的DMA区域。
    • 网卡完成物理发送。
  4. 资源清理和确认:
    • 发送完成后,网卡设备触发硬中断,释放与发送相关的资源,包括sk_buff内存和RingBuffer的清理。
    • 对于TCP数据包,当收到对方的ACK确认后,传输层释放保留的原始sk_buff副本。

发送网络数据的时候,涉及几次内存拷贝操作?

  1. 系统调用和sk_buff的初始分配:
    • 当应用程序第一次调用发送数据的系统调用时,内核为这些数据分配一个新的sk_buff
    • 用户空间的数据被复制到这个新分配的sk_buff中。
    • 这个sk_buff随后被加入到与Socket关联的发送缓冲区。
  2. TCP处理和sk_buff的克隆:
    • 在使用TCP协议时,传输层到网络层的过渡阶段中,为了支持TCP的可靠传输(重传机制),每个sk_buff被克隆为一个新副本。
    • 副本sk_buff(包含TCP头和数据)被传递到网络层,用于实际发送,而原始sk_buff则保留在传输层。
    • 当数据包发送完成且对应的ACK收到后,保留在传输层的原始sk_buff会被释放。
  3. IP层的分片处理:
    • 如果网络层(IP层)发现sk_buff的大小超过了MTU,它会进行分片处理。
    • 为此,内核会为每个分片数据包申请新的sk_buff
    • 原始sk_buff的内容被分割拷贝到新的sk_buff中,每个分片sk_buff包含原始数据包的一部分,并添加相应的IP头。

总结

  1. 应用层到传输层:
    • 应用程序通过Socket API发送数据,触发用户态到内核态的切换。
    • 内核分配sk_buff,将用户数据复制进去,并将其放入发送缓冲区。
    • 在传输层,如果使用TCP,数据可能会被分段以符合MSS的要求。
  2. 网络层处理:
    • 网络层选择路由(下一跳IP),填充IP头,执行netfilter过滤。
    • 如果数据包超过MTU,进行IP层的分片。
    • 分片后的数据包仍然封装在sk_buff结构体中。
  3. 网络接口层:
    • 通过ARP协议获取下一跳的MAC地址。
    • 填充数据链路层的帧头和帧尾到sk_buff
    • sk_buff放入网卡的发送队列。
  4. 硬件处理:
    • 触发软中断,通知网卡驱动有新的数据包待发送。
    • 网卡驱动从发送队列读取sk_buff,将其数据映射到网卡的DMA区域。
    • 网卡完成物理发送。
  5. 资源清理和确认:
    • 发送完成后,网卡设备触发硬中断,释放与发送相关的资源,包括sk_buff内存和RingBuffer的清理。
    • 对于TCP数据包,当收到对方的ACK确认后,传输层释放保留的原始sk_buff副本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1026396.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机软件安全

一、软件安全涉及的范围 1.1软件本身的安全保密 软件的本质与特征: 可移植性 寄生性 再生性 可激发性 攻击性 破坏性 …… 知识产权与软件盗版 软件商品交易形式不透明,方式多样,传统商标标识方法不适用; 盗版方法简捷…

蓝桥杯刷题之路径之谜

题目来源 路径之谜 不愧是国赛的题目 题意 题目中会给你两个数组,我这里是分别用row和col来表示 每走一步,往左边和上边射一箭,走到终点的时候row数组和col数组中的值必须全部等于0这个注意哈,看题目看了半天,因为…

ASP.Net添加Swagger注释

文章目录 Swagger添加Swagger注释 Swagger 添加Swagger注释 1、右击项目->选择属性->点击生成->输出,选中文档文件 2、配置服务 在program.cs 文件里配置SwaggerUI //增加项一 builder.Services.AddSwaggerGen(c> {c.SwaggerDoc("v1", ne…

策略路由-IP-Link-路由协议简介

策略路由 策略路由和路由策略的不同 1.策略路由的操作对象是数据包,在路由表已经产生的情况下,不按照路由表进行转发,而是根据需要,依照某种策略改变数据包的转发路径 2.路由策略的操作对象是路由信息。路由策略的主要实现了路…

基于Java中的SSM框架实现考研指导平台系统项目【项目源码+论文说明】

基于Java中的SSM框架实现考研指导平台系统演示 摘要 应对考研的学生,为了更好的使校园考研有一个更好的环境好好的学习,建议一个好的校园网站,是非常有必要的。提供学生的学习提供一个交流的空间。帮助同学们在学习高数、学习设计、学习统计…

web前端面试题----->VUE

Vue的数据双向绑定是通过Vue的响应式系统实现的。具体原理: 1. Vue会在初始化时对数据对象进行遍历,使用Object.defineProperty方法将每个属性转化为getter、setter。这样在访问或修改数据时,Vue能够监听到数据的变化。 2. 当数据发生变化时…

C语言-Win11安装古老的VC6.0

win11安装VC6 有些学校一直还在使用VC6.0,我们尝试在Win1 下安装这个老古董,以下是在win11下安装VC6.0的方法。 点击安装文件 输入产品序列号 修改公共安装文件夹 如果C盘空间足够可以不用修改。 此处会发现鼠标一直在转圈不能完成更新系统,可…

ChatGPT、千问、讯飞星火等在工作中提高效率

提升代码效率 通义灵码 适配性 100多种主流语言(C/C、Java、Python、Go、JavaScript、TypeScript等语言表现更为出色)支持常用 IDE(VS Code、IntelliJ IDEA、GoLand、PyCharm、WebStorm、CLion、PhpStorm、Android Studio、Xcode、iCoding…

记一次 .NET某游戏后端API服务 CPU爆高分析

一:背景 1. 讲故事 前几天有位朋友找到我,说他们的API服务程序跑着跑着CPU满了降不下去,让我帮忙看下怎么回事,现在貌似民间只有我一个人专注dump分析,还是申明一下我dump分析是免费的,如果想学习.NET高级…

进入消息传递的魔法之门:ActiveMQ原理与使用详解

嗨,亲爱的童鞋们!欢迎来到这个充满魔法的世界,今天我们将一同揭开消息中间件ActiveMQ的神秘面纱。如果你是一个对编程稍有兴趣,但又对消息中间件一知半解的小白,不要害怕,我将用最简单、最友好的语言为你呈…

电脑不能读取移动硬盘,但是可以读取U盘解决方法

找到此电脑 右键设备管理器,找到其中的通用串行总线控制器。 注意,凡是插入到电脑当中不能读取的U盘或者移动硬盘,都会在通用串行总线控制器当中显示为USB大容量存储设备 鼠标选中“USB大容量存储设备”,右键卸载它。此时&#x…

静态综合实验

一.搭建拓扑结构 1.根据拓扑结构可以把网段分成14个网段,根据192.168.1.0/24可以划分出ip地址和环回地址 其中环回r1分别是 192.168.1.32/27 192.168.1.32/28 192.168.1.48/28 2.划分完后如图: 二.配置IP地址 注意:为了避免错误&#…

【机器学习300问】49、数据预处理时如何处理类别型特征?

关于特征是什么?以及特征工程是什么意思?在先前我写的文章中已经为大家详细的介绍过了。本文想继续深入特征中的其中一种——类别型特征,来解答一个我自己遇到的困惑,同时记录成文章供大家一起学习。 【机器学习300问】14、什么是…

C++实现FFmpeg音视频实时拉流并播放

1.准备工作: 下载rtsp流媒体服务器rtsp-simple-server,安装go开发环境并编译 编译好后启动流媒体服务器 准备一个要推流的mp4视频文件,如db.mp4 使用ffmpeg开始推流 推流命令: ffmpeg -re -stream_loop -1 -i db.mp4 -c copy -rtsp_transport tcp -f rtsp rtsp://192.168.16…

前端学习之路-创建一个vue项目

每日吐槽:以工作为目的的学习就应该倒着推,任何一个岗位都可以先进去再学习,不管是培训班还是学校,知识点都有滞后性,虽然react被疯狂鼓吹但是Vue依然很抗打,学习的方法依然是百度老师的,以作记…

把本地文件上传到HDFS上操作步骤

因为条件有限,我这里以虚拟机centos为例 实验条件:我在虚拟机上创建了三台节点,部署了hadoop,把笔记本上的数据上传到hdfs中 数据打包上传到虚拟机节点上 采用的是rz命令,可以帮我们上传数据 没有的话可以使用命令安装…

开源流程图表库(02):Draw.io在线绘制各类图表,导出html使用

一、什么是Draw.io及其功能 Draw.io是一款免费的在线图表绘制工具,用于创建各种类型的图表和图形,如流程图、组织结构图、UML图、网络拓扑图、思维导图等。它提供了一个直观易用的界面,可以通过拖放和连接不同的图形元素来创建和编辑图表。 …

图神经网络实战(6)——使用PyTorch构建图神经网络

图神经网络实战(6)——使用PyTorch构建图神经网络 0. 前言1. 传统机器学习与人工智能2. 人工神经网络基础2.1 人工神经网络组成2.2 神经网络的训练 3. 图神经网络4. 使用香草神经网络执行节点分类4.1 数据集构建4.2 模型构建4.3 模型训练 5. 实现香草图神…

微服务篇-C 深入理解第一代微服务(SpringCloud)_V 深入理解Config分布式配置中心

原创作者:田超凡(程序员田宝宝) 版权所有,引用请注明原作者,严禁复制转载 Part 1 理论部分 1 什么是SpringCloud Config? 当一个系统中的配置文件发生改变的时候,我们需要重新启动该服务&am…

电脑访问网页获取路由器WAN口内网IP

因为运维过程中容易出现路由器配置了固定IP但是没人知道后台密码,不确定这个办公室的IP地址,且使用tracert路由追踪也只会出现路由器的LAN口网关并不会出现WAN口IP。 今日正好遇到了个好方法,经过测试可以正常使用。 方法如下: 内…