TCP/IP源码(59)——TCP中的三个接收队列
博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
======================================================================================================
在Linux内核的TCP实现中,TCP有三个接收队列——除去错误队列。这三个队列分别是struck sock中的sk_receive_queue和sk_backlog,以及struct tcp_sock中的prequeue。这三个队列作用,网上已经有很多文章论述了。这里只简单介绍一下,sk_receive_queue是真正的接收队列,收到的TCP数据包经过检查和处理后,就会保存到这个队列中。sk_backlog是当socket处于用户进程的上下文时(即用户正在对socket进行系统调用,如recv),Linux收到数据包时,在软中断处理过程中,会将数据包保存到sk_backlog中,然后直接返回。而prequeue则是在,该socket没有正在被用户进程使用时,由软中断直接将数据包保存在prequeue中,然后返回。
我们可以从tcp的接收处理函数中,验证上面的结果。下面的代码来自tcp_v4_rcv函数
1
2
3
|
bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { |
1
2
3
4
|
/* 当sock没有被用户进程占有的时候,可以将数据包保存到prequeue中。失败的话,才进入tcp的真正的数据包处理过程 */ if (!tcp_prequeue(sk, skb)) ret = tcp_v4_do_rcv(sk, skb); } else if (unlikely(sk_add_backlog(sk, skb))) { |
1
2
3
4
5
6
|
/* 当sock被用户进程占有时,将数据包保存到backlog中,然后返回 */ bh_unlock_sock(sk); NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP); goto discard_and_relse; } bh_unlock_sock(sk); |
1
|
<span style= "font-size:16px;" >在sock被用户进程占有时,kernel将数据包保存到backlog中,这个是可以理解的。因为即使是软中断处理流程,也需要尽快完成,好让kernel尽快处理</span><span style= "font-size:16px;" >下一个数据包。那么当</span><span style= "font-size:16px;line-height:24px;font-family:'sans serif', tahoma, verdana, helvetica;" >sock不被用户进程占有时,kernel将数据包保存到prequeue中,自然也是这个道理。这些数据包会在用户进程调用receive的时候,再进行TCP数据包完整的处理流程。</span> |
网上的大部分资料,都只是介绍了这三个队列的用途。但是看到这里,其实我们应该有一个疑问。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中保存。
TCP/IP源码(59)——TCP中的三个接收队列的更多相关文章
- TCP/IP协议栈在Linux内核中的运行时序分析
网络程序设计调研报告 TCP/IP协议栈在Linux内核中的运行时序分析 姓名:柴浩宇 学号:SA20225105 班级:软设1班 2021年1月 调研要求 在深入理解Linux内核任务调度(中断处理 ...
- 图解 TCP/IP 第六章 TCP与UDP 笔记6.1 传输层的作用
图解 TCP/IP 第六章 TCP与UDP 笔记6.1 传输层的作用 传输层必须指出这个具体的程序,为了实现这一功能,使用端口号这样一种识别码.根据端口号,就可以识别在传输层上一层的应用程 ...
- mysql-5.5.28源码安装过程中错误总结
介绍一下关于mysql-5.5.28源码安装过程中几大错误总结,希望此文章对各位同学有所帮助.系统centOS 6.3 mini (没有任何编译环境)预编译环境首先装了众所周知的 cmake(yum ...
- 2018-10-08 Java源码英翻中进展-内测上线
创建了一个子域名: http://translate.codeinchinese.com/ 欢迎试用, 如有建议/发现问题欢迎在此拍砖: program-in-chinese/code_transla ...
- 2018-09-24 Java源码英翻中网页演示
在线演示地址: 源代码翻译 两部分如下. 独立的Java代码翻译库 续前文代码翻译尝试-使用Roaster解析和生成Java源码 源码库: program-in-chinese/java_code_t ...
- TCP/IP解析(一):TCP/IP的工作方式
本文包括下面内容: 1.TCP/IP协议系统 2.OSI模型 3.数据包 4.TCP/IP的交互方式 1.TCP/IP模型的协议层 分为四层: 网络訪问层:提供与物理网络连接的接口.依据硬件的物理地址 ...
- 从源码看 Vue 中的 Mixin
最近在做项目的时候碰到了一个奇怪的问题,通过 Vue.mixin 方法注入到 Vue 实例的一个方法不起作用了,后来经过仔细排查发现这个实例自己实现了一个同名方法,导致了 Vue.mixin 注入方法 ...
- 将Android源码导入eclipse中的方法以及编译Android源码指定模块
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/53365659 将android源码导入eclipse.androidstudio. ...
- 源码解析.Net中IConfiguration配置的实现
前言 关于IConfituration的使用,我觉得大部分人都已经比较熟悉了,如果不熟悉的可以看这里.因为本篇不准备讲IConfiguration都是怎么使用的,但是在源码部分的解读,网上资源相对少一 ...
随机推荐
- ThinkPHP接入支付宝支付功能
最近做系统,需要实现在线支付功能,毫不犹豫,选择的是支付宝的接口支付功能.这里我用的是即时到帐的接口,具体实现的步骤如下: 一.下载支付宝接口包 下载地址:https://b.alipay.com/o ...
- cocos2dx调度器scheduler
/ 让帧循环调用this->update(float dt)函数 // scheduleUpdate(); // 让帧循环去调用制定的函数,时间还是1/60秒 // schedule(sched ...
- S5PV210开发板刷机(SD卡uboot、串口+USB-OTG刷机方法)
一.介绍 九鼎的S5PV210开发板,在出厂前已经默认刷了Android4.0系统.如果需要刷其它的系统或者是由于系统问题无法启动时,就需要对板子刷机. 其实,刷机是对210开发板的一个基础学习,目的 ...
- ACM竞赛常用STL(一)
全排列函数next_permutation STL 中专门用于排列的函数(可以处理存在重复数据集的排列问题) 头文件:#include <algorithm> using namespac ...
- map和lambda
同事问我python里,比如一个列表: a = ['1', '2', '3'] 如何变成: b = ['1x', '2x', '3x'] 好吧,果断不知道-原来pthon中有map函数,查看帮助文档: ...
- 关于C#的委托
作者 陈嘉栋(慕容小匹夫) 阅读目录 0x00 前言 0x01 从观察者模式说起 0x02 向Unity3D中的SendMessage和BroadcastMessage说拜拜 0x03 认识回调函数 ...
- 架设wordpress再vps上的 一些感想总结
日本vps.樱花系列 配置: 2cpu+1G内存+100G硬盘 系统 第一次我把默认的centos 给换了..原因就是,不会linux.而且我主要用.net 感觉 mono也行.但是linux不会. ...
- Js使用word书签填充内容
Js使用word书签填充内容 1.在模板文件中需要填充的地方插入书签 填充内容为:(|光标所在处) 填写书签名,点击添加完成: 2.使用js打开模板,获取书签位置,填充数据: function pri ...
- BZOJ 3570 动物园
Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习 ...
- Delphi控件的显示内容与显示边框是两回事
没有内容,不代表没有边框.比如设计期一个空的TImage仍是有边框的. if (csOpaque in image1.ControlStyle) then ShowMessage('不透明')else ...