UNIX网络编程8 从图中了解TCP协议在Linux内核中的实现

Packet Reception
UNIX网络编程8 从图中了解TCP协议在Linux内核中的实现_第1张图片
图1展示了一个新的包从网线进入到用户应用的路径。Linux 内核使用一个sk buff数据结构来描述每个packet。当一个packet到达网卡NIC时,它调用DMA引擎将packet放进内核内存中通过存储在一个环形buffer的空的sk buffs叫做rx ring。一个进入的packet如果环形缓冲区满了则被丢掉。当一个packet在较高协议层被处理时,packet数据仍然保留在相同的内核空间中,避免额外的内存复制。
当一个packet成功被接收,NIC网卡发出一个中断给CPU,处理每个进入的packet并且将它传递到IP层。IP协议层对每个数据包进行该层的处理程序,然后向上传递给TCP层如果它是一个TCP包的话。TCP处理程序然后处理这些包。每个包在TCP层进行了一系列复杂的处理步骤。TCP状态机被更新, 最后packet被存储进TCP recv buffer中
调节TCP的一个关键参数是receiver接收方的recv buffer的大小。一个TCP sender发送方发送数据包的能力是和 拥塞窗口cwnd最小值有关。 接收方的通告窗口的最大值是TCP recv buffer的大小。因此,如果recv buffer的大小比端到端的带宽延迟积BDP要小,则实际的吞吐量将会变低。recv buffer的大小可以修改/proc/sys/net/ipv4/tcp_rmem变量,里面有三个不同的值,分别是最小、默认、最大。
同样在接收方,参数netdev max backlog指示了packets在一个device排队的最大数量,等待TCP接收程序处理。


Packet Transmission
UNIX网络编程8 从图中了解TCP协议在Linux内核中的实现_第2张图片
在发送方,如图2,一个用户应用程序将数据写入到TCP发送缓冲区,通过调用write()系统调用。和TCP recv buffer类似,发送buffer 是一个重要参数对于获得最大的吞吐量来说。 拥塞窗口的最大值是和分配给TCP socket的发送缓冲区大小相关的。发送缓冲区保存着所有的外出包(为了可能的重传)。因此, 拥塞窗口的大小不能比发送缓冲区大,如果发送缓冲区太小,拥塞窗口将不会完全开放,限制了吞吐量。另一方面,大的发送缓冲区允许拥塞窗口增大到一个大值。如果不受TCP recv buffer的约束,外出的packets数量将会随着拥塞窗口的增长而增长,如果端到端路径不能承载这么多的外出packets将会造成丢包。 发送缓冲区的大小通过修改/proc/sys/net/ipv4/tcp_wmem变量
接收方的netdev max backlog是发送方的tx queue len。当数据在发送缓冲区就绪时,TCP层创建packets,或者是响应数据包收到的ACK packets。没个packet向下推到IP层。IP层将每个Packet入队到一个输出队列qdisc关联到NIC网卡。qdisc的大小可以修改,通过指定关联到每块网卡的tx queue len变量的值。如果输出队列满,将一个packet入队将造成一个本地拥塞事件,就会向上传递给TCP层。TCP拥塞控制算法就会进入拥塞窗口减小CWR状态。当一个packet成功放入到输出队列中,packet描述符sk buff然后就被放置到output ring buffer输出环形缓冲区中tx ring。当ring buffer中有packets可用,设备驱动就调用NIC的DMA引擎来传输packets到网线上。

你可能感兴趣的:(unix,tcp,实现,网络编程,内核)