您的位置:首页 > 理论基础 > 计算机网络

TCP/IP源码(59)——TCP中的三个接收队列

2013-11-10 18:59 253 查看
在Linux内核的TCP实现中,TCP有三个接收队列——除去错误队列。这三个队列分别是struck sock中的sk_receive_queue和sk_backlog,以及struct
tcp_sock中的prequeue。这三个队列作用,网上已经有很多文章论述了。这里只简单介绍一下,

1、sk_receive_queue是真正的接收队列,收到的TCP数据包经过检查和处理后,就会保存到这个队列中。

2、sk_backlog是当socket处于用户进程的上下文时(即用户正在对socket进行系统调用,如recv),Linux收到数据包时,在软中断处理过程中,会将数据包保存到sk_backlog中,然后直接返回。

3、而prequeue则是在,该socket没有正在被用户进程使用时,由软中断直接将数据包保存在prequeue中,然后返回。

我们可以从tcp的接收处理函数中,验证上面的结果。下面的代码来自tcp_v4_rcv函数

网上的大部分资料,都只是介绍了这三个队列的用途。但是看到这里,其实我们应该有一个疑问。backlog和prequeue都是保存的未经处理的数据,为什么需要两个不同的队列呢?为了解答这个疑问,我们需要研究一下prequeue和backlog是如何应用的?前面是两个队列的写入操作,下面看看两个队列何时被读取。prequeue的处理函数tcp_prequeue_process,如前文所说,在TCP的读取数据函数tcp_recvmsg中调用。在tcp_recvmsg的入口,会调用lock_sock来设置sk->sk_lock.owned,表示该sock由用户进程占有,然后会对receive_queue和prequeue中的数据包进行处理。正因为sock被用户进程处理时,会访问prequeu,所以软中断只能将数据保存到backlog中,以避免竞争。那么为什么在sock不由用户进程占有时,只能保存到prequeu中,而不能重入backlog呢?

让我们继续跟进,看看何时处理backlog的数据包。Oh,my god,居然是在__release_sock中,这真的有点出乎我的意料。这也就解释了,为什么需要两个队列来保存未处理数据包。对于sock来说,一共有两种状态:1. 用户进程占用该sock;2.
用户进程未占用该sock;而kernel需要在任何情况下,都要能够保证tcp数据包处理的软中断快速返回。而保存未处理数据包的队列,无论如何也要在上述的一个情况下,访问未处理的数据包。那么这不可避免的会有资源竞争。所以为了避免这种情况,当sock被用户进程占用时,让它处理prequeue中的数据包,软中断则往backlog中保存。当sock不被用户进程占用时,会去访问backlog中的数据包,软中断则往prequeue中保存。

http://blog.chinaunix.net/uid-20671208-id-3595604.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: