原文地址:TCP/IP源码学习(43)——__skb_recv_datagram学习 作者:GFree_Wind

作者:gfree.wind@gmail.com

博客:blog.focus-linux.net    linuxfocus.blog.chinaunix.net
Linux版本:2.6.36
好久没有看Linux源代码了,今天先回顾了一下以前的笔记,基本上把发送和接收数据包的流程学习了一遍。如果需要看以前的笔记,请看linuxfocus.blog.chinaunix.net上面的笔记。
不过以前的接收流程,只学习到kernel如何将数据包分发到对应的socket上。接收流程的其它部分没有太多值得关注的。我想可以这样去看源码,将一些有意思的部分单拿出来学习。
下面看一下UDP读取数据包的关键函数:
  1. struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
  2. int *peeked, int *err)
  3. {
  4. struct sk_buff *skb;
  5. long timeo;
  6. /*
  7. * Caller is allowed not to check sk->sk_err before skb_recv_datagram()
  8. */
  9. int error = sock_error(sk);
  10. if (error)
  11. goto no_packet;
     /* 当socket为阻塞时,获取timeout的值 */
  1. timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
  2. do {
  3. /* Again only user level code calls this function, so nothing
  4. * interrupt level will suddenly eat the receive_queue.
  5. *
  6. * Look at current nfs client by the way...
  7. * However, this function was corrent in any case. 8)
  8. */
  9. unsigned long cpu_flags;
         /* 
         当查看socket是否有数据包时,需要上锁,因为需要保证其它线程不会将数据包取走。
         */
  1. spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
  2. /* 查看在socket的buffer中是否有数据包 */
  3. skb = skb_peek(&sk->sk_receive_queue);
  4. if (skb) {
  5. *peeked = skb->peeked;
  6. if (flags & MSG_PEEK) {
  7. /*
  8. 设置MSG_PEEK,表示用户不是真的要读取数据,只是一个peek调用。
  9. 那么并不真正读取数据
  10. */
  11. skb->peeked = 1;
  12. atomic_inc(&skb->users);
  13. } else
  14. __skb_unlink(skb, &sk->sk_receive_queue); //从队列中取出数据,即可看作读出数据
  15. }
  16. spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
         // 有数据包,返回skb
  1. if (skb)
  2. return skb;
  3. /* User doesn't want to wait */
  4. error = -EAGAIN;
  5. /*
  6. timeo为0,有2中情况:1种是socket为非阻塞的,第2种,即socket阻塞的时间已经超过了timeo的值,
  7. 那么就跳到no_packet处理
  8. */
  9. if (!timeo)
  10. goto no_packet;
  11. } while (!wait_for_packet(sk, err, &timeo)); //阻塞进程,等待数据包
  12. return NULL;
  13. no_packet:
  14. *err = error;
  15. return NULL;
  16. }
下面看wait_for_packet:
  1. static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
  2. {
  3. int error;
     /* 
     前面的操作都是初始化wait,为将socket加入wait队列作准备,这部分代码牵涉到进程调度。关于进程调度,我      只是知道一些皮毛,留在以后学习。这里只需要将其看作是一些加入wait队列的准备工作即可,并不影响理解代码      。
     */
  1. DEFINE_WAIT_FUNC(wait, receiver_wake_function);
  2. prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
  1. /* Socket errors? */
  2. error = sock_error(sk);
  3. if (error)
  4. goto out_err;
     /* 一个完备检测。在决定wait和调用wait之间,有数据包到了,那么就不需要wait,所以这里再次检查socket      的队列是否为空 */
  1. if (!skb_queue_empty(&sk->sk_receive_queue))
  2. goto out;
     /* 完备检测。也许socket无数据包读取,因为socket已经被另外的线程关闭了。这样可以保证关闭socket的时      候,不会导致其他的socket的读写操作被阻塞。*/
  1. /* Socket shut down? */
  2. if (sk->sk_shutdown & RCV_SHUTDOWN)
  3. goto out_noerr;
      /* 对于面向连接的socket进行检查。如果是面向连接的socket,如果不是已经建立连接或者正在监听状态的so       cket是不可能有数据包的。不然即出错*/
  1. /* Sequenced packets can come disconnected.
  2. * If so we report the problem
  3. */
  4. error = -ENOTCONN;
  5. if (connection_based(sk) &&
  6. !(sk->sk_state == TCP_ESTABLISHED || sk->sk_state == TCP_LISTEN))
  7. goto out_err;
     /* 检查是否有pending的signal,保证阻塞时,进程可以被signal唤醒 */
  1. /* handle signals */
  2. if (signal_pending(current))
  3. goto interrupted;
  4. error = 0;
  5. /* sleep本进程,直至满足唤醒条件或者被信号唤醒——因为前面设置了TASK_INTERRUPTIBLE*/
  6. *timeo_p = schedule_timeout(*timeo_p);
  7. out:
     /* wait队列的清理工作 */
  1. finish_wait(sk_sleep(sk), &wait);
  2. return error;
  3. interrupted:
  4. error = sock_intr_errno(*timeo_p);
  5. out_err:
  6. *err = error;
  7. goto out;
  8. out_noerr:
  9. *err = 0;
  10. error = 1;
  11. goto out;
  12. }
看完了这两个函数,个人感觉这种针对一些有意义的函数进行学习,比流水账似的从系统调用开始学习的效果要好。因为后者会浪费很多精力在不太重要的代码或者流程上,而前者直接聚焦于比较关键的地方。

TCP/IP源码学习(43)——__skb_recv_datagram学习相关推荐

  1. [附源码]计算机毕业设计JAVA学习资源共享与在线学习系统

    [附源码]计算机毕业设计JAVA学习资源共享与在线学习系统 项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe ...

  2. 嵌入式之uboot源码分析-启动第二阶段学习笔记(下篇)

    接上部分---->嵌入式之uboot源码分析-启动第二阶段学习笔记(上篇) 注:如下内容来自朱老师物联网大讲堂uboot课件 3.2.14 CFG_NO_FLASH (1)虽然NandFlash ...

  3. 【Faster R-CNN论文精度系列】从Faster R-CNN源码中,我们“学习”到了什么?

    [Faster R-CNN论文精度系列] (如下为建议阅读顺序) 1[Faster R-CNN论文精度系列]从Faster R-CNN源码中,我们"学习"到了什么? 2[Faste ...

  4. 【 数据集加载 DatasetDataLoader 模块实现与源码详解 深度学习 Pytorch笔记 B站刘二大人 (7/10)】

    数据集加载 Dataset&DataLoader 模块实现与源码详解 深度学习 Pytorch笔记 B站刘二大人 (7/10) 模块介绍 在本节中没有关于数学原理的相关介绍,使用的数据集和类型 ...

  5. 【分类器 Softmax-Classifier softmax数学原理与源码详解 深度学习 Pytorch笔记 B站刘二大人(8/10)】

    分类器 Softmax-Classifier softmax数学原理与源码详解 深度学习 Pytorch笔记 B站刘二大人 (8/10) 在进行本章的数学推导前,有必要先粗浅的介绍一下,笔者在广泛查找 ...

  6. 【 反向传播算法 Back-Propagation 数学推导以及源码详解 深度学习 Pytorch笔记 B站刘二大人(3/10)】

    反向传播算法 Back-Propagation 数学推导以及源码详解 深度学习 Pytorch笔记 B站刘二大人(3/10) 数学推导 BP算法 BP神经网络可以说机器学习的最基础网络.对于普通的简单 ...

  7. 【 卷积神经网络CNN 数学原理分析与源码详解 深度学习 Pytorch笔记 B站刘二大人(9/10)】

    卷积神经网络CNN 数学原理分析与源码详解 深度学习 Pytorch笔记 B站刘二大人(9/10) 本章主要进行卷积神经网络的相关数学原理和pytorch的对应模块进行推导分析 代码也是通过demo实 ...

  8. 【 梯度下降算法 Gradient-Descend 数学推导与源码详解 深度学习 Pytorch笔记 B站刘二大人(2/10)】

    梯度下降算法 Gradient-Descend 数学推导与源码详解 深度学习 Pytorch笔记 B站刘二大人(2/10) 数学原理分析 在第一节中我们定义并构建了线性模型,即最简单的深度学习模型,但 ...

  9. 【多输入模型 Multiple-Dimension 数学原理分析以及源码详解 深度学习 Pytorch笔记 B站刘二大人 (6/10)】

    多输入模型 Multiple-Dimension 数学原理分析以及源码源码详解 深度学习 Pytorch笔记 B站刘二大人(6/10) 数学推导 在之前实现的模型普遍都是单输入单输出模型,显然,在现实 ...

最新文章

  1. 【hdu 1043】Eight
  2. 【目录】 网络瑞士军刀-netcat的秘诀
  3. Dapr微服务应用开发系列3:服务调用构件块
  4. python读取hadoop库数据_使用Python访问HDFS
  5. gatsby_将Gatsby默认启动程序转换为使用样式化组件
  6. Mac中使用LaTeX的中文字体出现Package fontspec Error: The font “宋体“ cannot be found.解决方案
  7. 时间预定java,在预定的时间运行任务java,apache
  8. 便宜可靠的激光雷达可能要来了!Luminar关键部件成本降到3美元
  9. Cython 的学习
  10. 第一章:Chrome 43 配置 java + selenium 环境
  11. eclipse java常用插件_高阶程序员必备25个最好的免费Eclipse插件
  12. 碰撞检测之 AABB 包围盒
  13. 隐马尔可夫python_隐马尔可夫模型原理和python实现
  14. 国美零售带货直播 重构本地零售数字化生产力
  15. [la P4487] Exclusive-OR
  16. 第2.2节 串行SPI接口控制PE4312数控衰减器
  17. JavaScript音频编辑
  18. Uva 10158 War
  19. c语言多线程编程随机数,在c 中使用线程安全的随机数,多线程_c_开发99编程知识库...
  20. Unity3D 实现背包系统

热门文章

  1. mysql 实现根据当前的位置信息,获取方圆20公里的数据库查询操作
  2. 苹果cms 蓝色repiannew主题模板
  3. 【集合类】 4 System:System.arraycopy方法解析
  4. 哈夫曼树原理及其构造方法
  5. 树莓派安装wiringPi库
  6. 免费路由器操作系统大汇总
  7. 全国医院查询 api数据接口
  8. 洛谷P1010 [NOIP1998 普及组] 幂次方
  9. tensorflow与keras
  10. Cache-主存地址映射