当前位置: 首页 > news >正文

深入理解Linux网络(二):UDP接收内核探究

深入理解Linux网络(二):UDP接收内核探究

  • 一、UDP 协议处理
  • 二、recvfrom 系统调⽤实现

一、UDP 协议处理

udp 协议的处理函数是 udp_rcv。

//file: net/ipv4/udp.c
int udp_rcv(struct sk_buff *skb)
{return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP);
}int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, int proto)
{sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);if (sk != NULL) {int ret = udp_queue_rcv_skb(sk, skb);}icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
}

__udp4_lib_lookup_skb 是根据 skb 来寻找对应的socket,当找到以后将数据包放到
socket 的缓存队列⾥。如果没有找到,则发送⼀个⽬标不可达的 icmp 包。

//file: net/ipv4/udp.c
int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{ ......if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf))goto drop;rc = 0;ipv4_pktinfo_prepare(skb);bh_lock_sock(sk);if (!sock_owned_by_user(sk))rc = __udp_queue_rcv_skb(sk, skb);else if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) {bh_unlock_sock(sk);goto drop;}bh_unlock_sock(sk);return rc;
}

sock_owned_by_user 判断的是⽤户是不是正在这个 socket 上进⾏系统调⽤( socket 被占⽤)。
如果没有,那就可以直接放到 socket 的接收队列中。
如果有,那就通过 sk_add_backlog 把数据包添加到 backlog 队列。 当⽤户释放的 socket 的时候,内核会检查 backlog 队列,如果有数据再移动到接收队列中。
sk_rcvqueues_full 接收队列如果满了的话,将直接把包丢弃。接收队列⼤⼩受内核参数
net.core.rmem_max 和 net.core.rmem_default 影响。

二、recvfrom 系统调⽤实现

代码⾥调⽤的 recvfrom 是⼀个 glibc 的库函数,该函数在执⾏后会将⽤户进⾏陷⼊到内核态,进⼊到 Linux 实现的系统调⽤ sys_recvfrom 。
在这里插入图片描述
socket 数据结构中的 const struct proto_ops 对应的是协议的⽅法集合。每个协议都会实现不同的⽅法集,对于IPv4 Internet 协议族来说,每种协议都有对应的处理⽅法,如下:
对于 udp 来说,是通过 inet_dgram_ops 来定义的,其中注册了 inet_recvmsg ⽅法。

//file: net/ipv4/af_inet.c
const struct proto_ops inet_stream_ops = {.......recvmsg = inet_recvmsg,.mmap = sock_no_mmap,......
}
const struct proto_ops inet_dgram_ops = {.......sendmsg = inet_sendmsg,.recvmsg = inet_recvmsg,......
}

socket 数据结构中的另⼀个数据结构 struct sock *sk 是⼀个⾮常⼤,⾮常重要的⼦结构体。其中的 sk_prot ⼜定义了⼆级处理函数。对于udp协议来说,会被设置成 udp 协议实现的⽅法集 udp_prot 。

//file: net/ipv4/udp.c
struct proto udp_prot = {.name = "UDP",.owner = THIS_MODULE,.close = udp_lib_close,.connect = ip4_datagram_connect,.......sendmsg = udp_sendmsg,.recvmsg = udp_recvmsg,.sendpage = udp_sendpage,......
}

看完了 socket 变量之后,我们再来看 sys_recvfrom 的实现过程。
在这里插入图片描述
在 inet_recvmsg 调⽤了 sk->sk_prot->recvmsg 。

//file: net/ipv4/af_inet.c
int inet_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg,size_t size, int flags)
{ ......err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags &
MSG_DONTWAIT,flags & ~MSG_DONTWAIT, &addr_len);if (err >= 0)msg->msg_namelen = addr_len;return err;
}//file: net/core/datagram.c:EXPORT_SYMBOL(__skb_recv_datagram);
struct sk_buff *__skb_recv_datagram(struct sock *sk, unsignedint flags, int *peeked, int *off, int *err)
{......do {struct sk_buff_head *queue = &sk->sk_receive_queue;skb_queue_walk(queue, skb) {......}/* User doesn't want to wait */error = -EAGAIN;if (!timeo)goto no_packet;} while (!wait_for_more_packets(sk, err, &timeo, last));
}

上⾯所谓的读取过程,就是访问 sk->sk_receive_queue 。
如果没有数据,且⽤户也允许等待,则将调⽤ wait_for_more_packets() 执⾏等待操作,它加⼊会让⽤户进程进⼊睡眠状态。
具体是怎么进⼊睡眠状态的,和 TCP 的实现一样,属于进程的基本知识了。

再次推荐飞哥的 《深入理解Linux网络》。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • tg小程序前端-dogs前端源码分析
  • mongodb数据导出与导入
  • 【20】读感 - 架构整洁之道(二)
  • 基于springboot+vue+uniapp的农场管理系统小程序
  • Yum包下载
  • 【python doris】python连接doris数据库,并查询返回数据框
  • <数据集>pcb板缺陷检测数据集<目标检测>
  • Socket、WebSocket 和 MQTT 的区别
  • c++基础(类和对象中)(类的默认成员函数)
  • 使用Event Sourcing模式管理应用状态
  • c++图的基本操作
  • 塔子哥的题解点赞方案-美团2023笔试(codefun2000)
  • 递归遍历树结构,前端传入一整颗树,后端处理这个树,包括生成树的id和pid等信息,
  • WhisperX
  • 《Nginx核心技术》第04章:生成缩略图
  • 【笔记】你不知道的JS读书笔记——Promise
  • git 常用命令
  • iOS编译提示和导航提示
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • SpringBoot几种定时任务的实现方式
  • ViewService——一种保证客户端与服务端同步的方法
  • 不上全站https的网站你们就等着被恶心死吧
  • 如何用vue打造一个移动端音乐播放器
  • 手机端车牌号码键盘的vue组件
  • 一些css基础学习笔记
  • 正则表达式
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • ​必胜客礼品卡回收多少钱,回收平台哪家好
  • #if #elif #endif
  • ${factoryList }后面有空格不影响
  • (9)STL算法之逆转旋转
  • (初研) Sentence-embedding fine-tune notebook
  • (待修改)PyG安装步骤
  • (七)Flink Watermark
  • (循环依赖问题)学习spring的第九天
  • (一)十分简易快速 自己训练样本 opencv级联haar分类器 车牌识别
  • *算法训练(leetcode)第四十七天 | 并查集理论基础、107. 寻找存在的路径
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .net2005怎么读string形的xml,不是xml文件。
  • .NetCore项目nginx发布
  • .Net的C#语言取月份数值对应的MonthName值
  • .net实现头像缩放截取功能 -----转载自accp教程网
  • .Net组件程序设计之线程、并发管理(一)
  • @Autowired和@Resource装配
  • @configuration注解_2w字长文给你讲透了配置类为什么要添加 @Configuration注解
  • @data注解_一枚 架构师 也不会用的Lombok注解,相见恨晚
  • [8481302]博弈论 斯坦福game theory stanford week 1
  • [C# 基础知识系列]专题十六:Linq介绍
  • [C++]打开新世界的大门之C++入门
  • [caffe(二)]Python加载训练caffe模型并进行测试1
  • [cocos creator]EditBox,editing-return事件,清空输入框