Linux中一个网络包的发送/接收流程
内容提要
本文介绍了Linux中网络包的协议头封装与解析过程,以及粘包拆包现象的原因。文章详细解析了sk_buff数据结构和发送窗口、接收窗口的工作原理。此外,还比较了不同的网络包发送函数的拷贝次数。
延伸解读
粘包与拆包:缓冲区合并与MSS限制
文章指出,粘包现象与发送缓冲区的合并机制有关。当发送队列中存在未被ACK的sk_buff,且新数据未达到MSS/MTU限制、缓冲区未达SO_SENDBUF上限时,Linux会尝试将新数据合并到最后一个sk_buff中,导致多个应用层报文被合并成一个网络包发送。拆包则可能发生在数据超过MSS/MTU时,需要分片传输。理解这一机制有助于诊断网络通信中的边界问题。
发送窗口与接收窗口:流量控制与内存管理
发送窗口大小由SO_SENDBUF决定,但内核实际分配时会考虑自身数据结构开销,因此可能加倍。发送时若缓冲区已满,线程会阻塞睡眠,直到有包被ACK后触发内存释放回调唤醒。接收窗口分为已接收未读取、可接收和未预分配三部分,用户进程读取数据后窗口左端右移并释放内存。这些机制共同实现了TCP的流量控制和内存管理。
零拷贝技术选型:sendFile与mmap+write的适用场景
文章比较了不同发送函数的拷贝次数。read+write需要两次系统调用、两次CPU拷贝和两次DMA拷贝。sendFile减少了一次CPU拷贝,但只能传输文件页且无法添加用户态协议数据,适合Kafka等大文件传输。mmap+write通过映射PageCache避免立即拷贝,适合小文件如RocketMQ的消息传输,但大文件会频繁触发缺页异常。选型需根据数据大小和协议需求权衡。
Q&A
Linux中网络包的发送流程是怎样的?
Linux中网络包的发送流程包括用户态进程通过write()系统调用将数据写入套接字缓冲区,经过TCP处理后添加协议头,最终通过网卡的DMA将数据发送出去。
什么是sk_buff数据结构,它的作用是什么?
sk_buff数据结构是Linux实现网络协议栈的核心,包含不同协议头的指针,用于管理网络包的发送和接收。
粘包和拆包现象的原因是什么?
粘包和拆包现象的原因与网络包的缓冲区和拷贝过程有关,特别是在发送缓冲区存在积压时,Linux会尝试将当前包合并到最后一个sk_buff结构中。
TCP的滑动窗口和拥塞窗口有什么区别?
TCP的滑动窗口用于控制已发送但未确认的数据量,而拥塞窗口则用于控制网络中可发送的数据量,以避免网络拥塞。
sendFile系统调用与传统的write系统调用有什么不同?
sendFile系统调用减少了拷贝次数,直接将PageCache中的数据拷贝到套接字缓冲区,而write系统调用需要先将数据拷贝到用户态内存中。
如何查看Linux中套接字的发送和接收缓冲区状态?
可以通过ss -nt命令查看当前套接字的发送和接收缓冲区状态。