安庆哪些做网站的公司好,怎么做网站里的悬浮窗口,wordpress 底部修改插件,wordpress关键字查询一、接收网络包的过程
引言 网卡是计算机里的一个硬件#xff0c;专门负责接收和发送网络包#xff0c;当网卡接收到一个网络包后#xff0c;会通过 DMA 技术#xff0c;将网络包写入到指定的内存地址#xff0c;也就是写入到 Ring Buffer #xff0c;这个是一个…一、接收网络包的过程
引言 网卡是计算机里的一个硬件专门负责接收和发送网络包当网卡接收到一个网络包后会通过 DMA 技术将网络包写入到指定的内存地址也就是写入到 Ring Buffer 这个是一个环形缓冲区接着就会告诉操作系统这个网络包已经到达。
DMA是直接存储器访问主要替代CPU读取磁盘数据到内核缓冲区的过程 那应该怎么告诉操作系统这个网络包已经到达了呢 最简单的一种方式就是触发中断也就是每当网卡收到一个网络包就触发一个中断告诉操作系统。 但是这存在一个问题在高性能网络场景下网络包的数量会非常多那么就会触发非常多的中断要知道当 CPU 收到了中断就会停下手里的事情而去处理这些网络包处理完毕后才会回去继续其他事情那么频繁地触发中断则会导致 CPU 一直没完没了的处理中断而导致其他任务可能无法继续前进从而影响系统的整体效率。 所以为了解决频繁中断带来的性能开销Linux 内核在 2.6 版本中引入了 NAPI 机制它是混合「中断和轮询」的方式来接收网络包它的核心概念就是不采用中断的方式读取数据而是首先采用中断唤醒数据接收的服务程序然后 poll 的方法来轮询数据。
预处理
当有网络包到达时会通过 DMA 技术将网络包写入到指定的内存地址接着网卡向 CPU 发起硬件中断当 CPU 收到硬件中断请求后根据中断表调用已经注册的中断处理函数。
硬件中断处理函数会做如下的事情
需要先「暂时屏蔽中断」表示已经知道内存中有数据了告诉网卡下次再收到数据包直接写内存就可以了不要再通知 CPU 了这样可以提高效率避免 CPU 不停的被中断。接着发起「软中断」然后恢复刚才屏蔽的中断。
至此硬件中断处理函数的工作就已经完成。
硬件中断处理函数做的事情很少主要耗时的工作都交给软中断处理函数了。 软中断的处理 内核中的 ksoftirqd 线程专门负责软中断的处理当 ksoftirqd 内核线程收到软中断后就会来轮询处理数据。
ksoftirqd 线程会从 Ring Buffer 中获取一个数据帧用 sk_buff 表示从而可以作为一个网络包交给网络协议栈进行逐层处理。 网络协议栈 1、网络接口层
首先会先进入到网络接口层在这一层会检查报文的合法性如果不合法则丢弃合法则会找出该网络包的上层协议的类型比如是 IPv4还是 IPv6接着再去掉帧头和帧尾然后交给网络层。
2、网络层
到了网络层则取出 IP 包判断网络包下一步的走向比如是交给上层处理还是转发出去。当确认这个网络包要发送给本机后就会从 IP 头里看看上一层协议的类型是 TCP 还是 UDP接着去掉 IP 头然后交给传输层。
3、传输层
传输层取出 TCP 头或 UDP 头根据四元组「源 IP、源端口、目的 IP、目的端口」 作为标识找出对应的 Socket并把数据放到 Socket 的接收缓冲区。
4、应用层
最后应用层程序调用 Socket 接口将内核的 Socket 接收缓冲区的数据「拷贝」到应用层的缓冲区然后唤醒用户进程。
至此一个网络包的接收过程就已经结束了。
二、发送网络包的过程
预处理 首先应用程序会调用 Socket 发送数据包的接口由于这个是系统调用所以会从用户态陷入到内核态中的 Socket 层内核会申请一个内核态的 sk_buff 内存将用户待发送的数据拷贝到 sk_buff 内存并将其加入到发送缓冲区。 接下来网络协议栈从 Socket 发送缓冲区中取出 sk_buff并按照 TCP/IP 协议栈从上到下逐层处理。
1、传输层
如果使用的是 TCP 传输协议发送数据那么先拷贝一个新的 sk_buff 副本 这是因为 sk_buff 后续在调用网络层最后到达网卡发送完成的时候这个 sk_buff 会被释放掉。而 TCP 协议是支持丢失重传的在收到对方的 ACK 之前这个 sk_buff 不能被删除。所以内核的做法就是每次调用网卡发送的时候实际上传递出去的是 sk_buff 的一个拷贝等收到 ACK 再真正删除
至此传输层的工作也就都完成了。
2、网络层
然后交给网络层在网络层里会做这些工作选取路由确认下一跳的 IP、填充 IP 头、netfilter 过滤、对超过 MTU 大小的数据包进行分片。处理完这些工作后会交给网络接口层处理。
3、网络接口层
网络接口层会通过 ARP 协议获得下一跳的 MAC 地址然后对 sk_buff 填充帧头和帧尾接着将 sk_buff 放到网卡的发送队列中。
这一些工作准备好后会触发「软中断」告诉网卡驱动程序这里有新的网络包需要发送驱动程序会从发送队列中读取 sk_buff将这个 sk_buff 挂到 RingBuffer 中接着将 sk_buff 数据映射到网卡可访问的内存 DMA 区域最后触发真实的发送。
当数据发送完成以后其实工作并没有结束因为内存还没有清理。当发送完成的时候网卡设备会触发一个硬中断来释放内存主要是释放 sk_buff 内存和清理 RingBuffer 内存。
最后当收到这个 TCP 报文的 ACK 应答时传输层就会释放原始的 sk_buff 。