深入理解Linux网络(四):TCP接收阻塞

news2024/12/25 2:11:06

TCP socket 接收函数 recv 发出 recvfrom 系统调用。
进⼊系统调⽤后,⽤户进程就进⼊到了内核态,通过执⾏⼀系列的内核协议层函数,然后到 socket 对象的接收队列中查看是否有数据,没有的话就把⾃⼰添加到 socket 对应的等待队列⾥。最后让出CPU,操作系统会选择下⼀个就绪状态的进程来执⾏。
在这里插入图片描述
假如我们没有使⽤ O_NONBLOCK 标记,等待接收的过程会阻塞进程,但是我们先探究阻塞的过程。

//file: net/socket.c
SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t,
 size, unsigned int, flags, struct sockaddr __user *, addr,
 int __user *, addr_len)
{
 struct socket *sock;
 //根据⽤户传⼊的 fd 找到 socket 对象
 sock = sockfd_lookup_light(fd, &err, &fput_needed);
 ......
 err = sock_recvmsg(sock, &msg, size, flags);
 ......
}

sock_recvmsg -> __sock_recvmsg -> __sock_recvmsg_nosec

static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
 struct msghdr *msg, size_t size, int flags)
{
 ......
 return sock->ops->recvmsg(iocb, sock, msg, size, flags);
}

在之前的 socket 对象图中,从图中看到 recvmsg 指向的是 inet_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);

这里又出现了一个 recvmsg 函数指针,不过这个是socket 对象中的 recvmsg 方法,对应 TCP 协议的 tcp_recvmsg 方法。

//file: net/ipv4/tcp.c
int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 size_t len, int nonblock, int flags, int *addr_len)
{
 int copied = 0;
 ...
 do {
  //遍历接收队列接收数据
  skb_queue_walk(&sk->sk_receive_queue, skb) {
  ...
 }
 ...
 }
 if (copied >= target) {
  release_sock(sk);
  lock_sock(sk);
  } else //没有收到⾜够数据,启⽤ sk_wait_data 阻塞当前进程
  sk_wait_data(sk, &timeo);
}

可以看到,消息量不够,一样也会阻塞。
在这里插入图片描述
如果没有收到数据,或者收到不⾜够多,则调⽤ sk_wait_data 把当前进程阻塞掉。

//file: net/core/sock.c
int sk_wait_data(struct sock *sk, long *timeo)
{
 //当前进程(current)关联到所定义的等待队列项上
 DEFINE_WAIT(wait);
 // 调⽤ sk_sleep 获取 sock 对象下的 wait
 // 并准备挂起,将进程状态设置为可打断 INTERRUPTIBLE
 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
 // 通过调⽤schedule_timeout让出CPU,然后进⾏睡眠
 rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue));
 ...

sk_wait_data 阻塞进程的实现:
在这里插入图片描述
做完排队工作后,给所在进程改个状态位即可。
⾸先在 DEFINE_WAIT 宏下,定义了⼀个等待队列项 wait。 在这个新的等待队列项上,注册了回调函数 autoremove_wake_function,并把当前进程描述符 current 关联到其 .private 成员上。

//file: include/linux/wait.h
#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
#define DEFINE_WAIT_FUNC(name, function) \
 wait_queue_t name = { \
 .private = current, \
 .func = function, \
 .task_list = LIST_HEAD_INIT((name).task_list), \
 }

紧接着在 sk_wait_data 中 调⽤ sk_sleep 获取 sock 对象下的等待队列列表头 wait_queue_head_t。
sk_sleep 源代码如下:

//file: include/net/sock.h
static inline wait_queue_head_t *sk_sleep(struct sock *sk)
{
 BUILD_BUG_ON(offsetof(struct socket_wq, wait) != 0);
 return &rcu_dereference_raw(sk->sk_wq)->wait;
}

接着调⽤ prepare_to_wait 来把新定义的等待队列项 wait 插⼊到 sock 对象的等待队下。

//file: kernel/wait.c
void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
{
 unsigned long flags;
 wait->flags &= ~WQ_FLAG_EXCLUSIVE;
 spin_lock_irqsave(&q->lock, flags);
 if (list_empty(&wait->task_list))
 __add_wait_queue(q, wait);
 set_current_state(state);
 spin_unlock_irqrestore(&q->lock, flags);
}

这样后⾯当内核收完数据产⽣就绪时间的时候,就可以查找 socket 等待队列上的等待项,进⽽就可以找到回调函数和在等待该 socket 就绪事件的进程了。
最后再调⽤ sk_wait_event 让出 CPU,进程将进⼊睡眠状态,这会导致⼀次进程上下⽂的开销。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1939861.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MYSQL——库表操作

MYSQL——库表操作 1.1 SQL语句基础1.1.1. SQL简介1.1.2. SQL语句分类1.1.3. SQL语句的书写规范 1.2 数据库的操作1.2.1 数据库的登录及退出1.2.2 查看数据库1.2.3 创建数据库1.2.4 切换数据库1.2.5 查看当前用户1.2.6 删除数据库 1.3 MySQL字符集1.3.1. 字符集1.3.2. 字符序1.…

myBatis的基本操作(持续更新中。。。)

目录 1. 简介2. 简单使用3. 代理开发4. 小技巧5. 动态查询6. 注解&#xff08;待更新&#xff09;底部 1. 简介 mybatis是一款优秀的持久层框架&#xff0c;用来简化JDBC开发 持久层&#xff1a;负责将数据保存到数据库的那一层代码 2. 简单使用 依赖 <dependencies>…

LabVIEW断路器操动机构运动速度检测

开发了一种基于LabVIEW设计平台开发的断路器操动机构运动速度检测系统。通过集成高速相机和图像处理技术&#xff0c;该系统能够实时监控和分析操动机构的动态性能&#xff0c;为电力系统提供关键的技术支持。 项目背景 随着工业化的发展&#xff0c;对电力系统的稳定性和可靠…

python的tkinter、socket库开发tcp的客户端和服务端

一、tcp通讯流程和开发步骤 1、tcp客户端和服务端通讯流程图 套接字是通讯的利器&#xff0c;连接时要经过三次握手建立连接&#xff0c;断开连接要经过四次挥手断开连接。 2、客户端开发流程 1&#xff09;创建客户端套接字 2&#xff09;和服务端器端套接字建立连接 3&#x…

钡铼分布式I/O系统边缘计算Modbus,MQTT,OPC UA耦合器BL206

BL206系列耦合器是一个数据采集和控制系统&#xff0c;基于强大的32 位微处理器设计&#xff0c;采用Linux操作系统&#xff0c;支持Modbus&#xff0c;MQTT&#xff0c;OPC UA协议&#xff0c;可以快速接入现场PLC、DCS、PAS、MES、Ignition和SCADA以及ERP系统&#xff0c;同时…

习题2.21

(defn rever [a](defn item[l r](if ( nil (first l)) r(item (rest l) (cons (first l) r))))(item a nil)) 这段代码非常有助于理解什么是深度优先&#xff0c;什么是广度优先。 很久没有写习题的代码了&#xff0c;倒不是懒得做习题了&#xff0c;是私事多&#xff0c;状态…

【局域网服务器连接】如何远程连入实验室linux系统服务器?| 局域网 | 内网穿透

文章目录 前言服务器基本配置安装 ssh 服务防火墙放行 局域网内网穿透获取SN码添加映射 总结 前言 简单记录连接实验室服务器步骤。如服务器直接有公网 ip 地址&#xff0c;ssh 直接连入即可&#xff0c;无需参考本文。 与服务器连同一 wifi&#xff0c; 参考 局域网 方式连接…

Android:requestLayout、invalidate 和 postInvalidate 的区别

提醒&#xff1a;下面源码来自SDK里Android-34版本 一、requestLayout 点击查看requestLayout官网文档 1.1 requestLayout方法源码 /*** Call this when something has changed which has invalidated the* layout of this view. This will schedule a layout pass of the v…

【C++航海王:追寻罗杰的编程之路】关于空间配置器你知道多少?

目录 1 -> 什么是空间配置器 2 -> 为什么需要空间配置器 3 -> SGI-STL空间配置器的实现原理 3.1 -> 一级空间配置器 3.2 -> 二级空间配置器 3.2.1 -> 内存池 3.2.2 -> SGI-STL中二级空间配置器设计 3.2.3 -> SGI-STL二级空间配置器之空间申请 …

Spring Boot 3.3 【三】Spring Boot RESTful API 增删改查详细教程

Spring Boot RESTful API 增删改查详细教程 一、RESTful 架构风格简介 1. 简介 RESTful API 是一种基于HTTP协议的网络应用接口设计风格&#xff0c;它遵循REST&#xff08;Representational State Transfer&#xff0c;表述性状态转移&#xff09;原则。RESTful架构风格的出…

花几千上万学习Java,真没必要!(二十)

ArrayList 是一种可以动态增长和缩减的数组&#xff0c;与普通的数组相比&#xff0c;它提供了更加灵活的操作方式。ArrayList 内部使用数组来存储元素&#xff0c;但是它会根据需要自动调整数组的大小&#xff0c;以便能够存储更多的元素。 ArrayList 的主要特点包括&#xf…

如何成为学习高手

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 所有的学习方式&#xff0c;核心都是动脑加动手。 区别在于如何让…

吴恩达大模型LLM系列课程学习(更新42门课程)

目录 GPT-4o详细中文注释的Colab中英文字幕观看视频1 浏览器下载插件2 打开官方视频 课程1&#xff1a;Prompt Compression and Query Optimization课程2&#xff1a;Carbon Aware Computing for GenAI developers课程3&#xff1a;Function-calling and data extraction with …

Java语言程序设计——篇六(1)

字符串 概述创建String类对象     字符串基本操作实战演练 字符串查找字符串转换为数组字符串比较实战演练 字符串的拆分与组合 概述 字符串 用一对双引号“”括起来的字符序列。Java语言中&#xff0c;字符串常量或变量均用类实现。 字符串有两大类&#xff1a; 1&…

2024年【起重机司机(限桥式起重机)】考试题及起重机司机(限桥式起重机)新版试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 起重机司机(限桥式起重机)考试题参考答案及起重机司机(限桥式起重机)考试试题解析是安全生产模拟考试一点通题库老师及起重机司机(限桥式起重机)操作证已考过的学员汇总&#xff0c;相对有效帮助起重机司机(限桥式起重…

JS 原型与原型链图解:彻底搞懂的终极指南

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热爱技术和分享&#xff0c;欢迎大家交流&#xff0c;一起学习进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 在JavaScript中&#xff0c;原型和原型链是非常重要的知识点&#xff0c;只有理解了…

Express+mysql单表分页条件查询

声明&#xff08;自己还没测试过&#xff0c;只提供大概逻辑&#xff0c;什么多表连接查询可以在原基础上添加&#xff09; class /*** param connection Express的mysql数据库链接对象* current 当前页* pageSize 一页显示行数* where [{key:id,operator:,value15}], key查询…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 卢小姐的生日礼物(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

pg_restore导入错误的解决思路

背景 开发使用postgresql 数据库&#xff0c;当需要部署时&#xff0c;通过pg_dump导出&#xff0c;通过pg_restore导入&#xff0c;发现导入遇到错误&#xff0c;很多表没有导入。部分报错截图如下&#xff1a; 排查问题 开发中用到了postgresql插件postgis里的地理类型&am…

ORBSLAM3 ORB_SLAM3 Ubuntu20.04 ROS Noetic 虚拟机镜像 下载

下图是build.sh 和 build_ros.sh编译结果截图&#xff1a; slam数据集测试视频&#xff1a; orbslam3 ubuntu20.04 test 下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1nre0Y9vig5QXIGU52qCLbQ?pwd9rbi 提取码&#xff1a;9rbi