TCP/IP网络栈实现

参考 翻译:理解TCP/IP网络栈&编写网络应用一文内容。

1. TCP/IP的特性

  1. 面向连接
    这里的连接用什么结构管理?
  2. 双向字节流
    字节流是什么意思?
  3. 顺序投递
    能够完全遵循时间顺序投递?
  4. ACK实现可靠性
    怎么可靠?
  5. 流量控制、阻塞控制

2. 数据传输流程

网络栈很多层
image

内核层使用socket(因为抽象成文件,会走VFS路径)来管理从用户区拷贝过来的接收与发送的数据缓冲区,socket会关联一个TCP控制块,其包含TCP连接的所有状态数据。(基本回答问题1)

TCP中允许情况下会创建TCP segment,包含两个部分:TCP头+数据,注意TCP校验和不会中内核中算出,会offload到NIC中处理
image

创建的TCP分段进入IP层中增加IP头,然后执行IP路由(之后下一层是链路层增加链路头,至此形成完整报文)在执行IP路由时回选择一个NIC传输接口,这时会调用NIC驱动程序。如果此时有抓包程序则会在此层进行数据拷贝处理。驱动程序与内核通过请求NIC定义的通讯协议进行传输。

NIC会从系统内存中拷贝数据包,向数据包中增加帧间隙(Inter-Frame Gap,IFG),同步码(preamble)和crc校验和。帧间隙和同步码用于区分数据包的开始(NIC目前是在哪一层?)。NIC会在主机的CPU上产生中断。驱动程序在启动时会注册一个处理中断的函数。操作系统调用中断处理程序,之后中断处理程序会把已发送的数据包返回给操作系统。

除了应用程序直接调用write之外,内核也可以直接调用TCP传输数据,比如接收到ACK并且得知接收方的接收窗口增大之后,内核会创建socket缓冲区剩余数据的TCP片段并且把数据发送给接收者。

3.数据接收流程

NIC接收到数据包后计算CRC,然后拷贝到驱动提前向内核申请的缓冲区中,之后NIC发出中断。驱动程序会判断它是否能处理新的数据包。
image

驱动向上层发送数据包时,Linux的sk_buff,或者BSD系列内核的mbuf,或者windows的NET_BUFFER_LIST。驱动会把数据包包装成指定的数据结构,并发送到上一层。

之后数据链路层,IP层同样检查数据包是否有效,最后到TCP层查找到对应的TCB,socket接收缓冲区的大小就是TCP接收窗口。TCP吞吐量会随着接收窗口变大而增加。

4. 流量控制

image

步骤3即使用定时器超时机制

5. 中断处理

中断比较复杂,例如NIC接收数据产生中断,驱动在释放已经传输的数据包之后调用napi_schedule()函数去处理接收到的数据包,这个函数会请求软中断。
image

在中断上下文被执行之后,软中断的上下文会被执行。中断上下文和软中断上下文会通过相同的线程执行,但是它们会使用不同的栈。并且中断上下文会屏蔽硬件中断;而软中断上下文不会屏蔽硬件中断。

处理接收到的数据包的软中断处理程序是net_rx_action()函数。这个函数会调用驱动程序的poll()函数。而poll()函数会调用netif_receive_skb()函数,并把接收到的数据包一个接一个的发送到上层。在软中断处理结束后,应用程序会从停止的位置重新开始执行完成系统调用。所以才有多队列NIC以解决软中断并发处理瓶颈问题。

本站总访问量