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

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// 并准备挂起,将进程状态设置为可打断 INTERRUPTIBLEprepare_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.mzph.cn/news/874249.shtml

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

相关文章

Conda和Pip有什么区别?

conda和pip是Python中两种常用的包管理工具,它们在用途、包来源以及环境管理等方面存在区别。以下是具体分析: 用途 conda:conda是Anaconda发行版中的包管理工具,可以管理包括非Python软件包在内的各种包。它是一个全面的环境管理…

为什么企业一定要多参加展会,参展有何好处?

在当今的商业环境中,展会已成为企业不可或缺的市场推广和交流平台。无论企业规模大小,参展都是一个极其有益的选择。以下,我们将深入探讨企业为何要多参加展会,以及参展所能带来的种种好处。 一、增强品牌影响力与知名度 展会是聚…

大数据量接口响应慢-传输优化

问题 接口一次性返回大量数据,导致JSON数据大小过大,带宽大小不足,导致接口响应时间过长 解决方案 通过数据传输压缩来降低传输数据的大小,从而提高传输效率 服务器端压缩 springboot项目配置application文件,通过…

视频翻译保留原音色pyvideotrans+clone-voice

剪映的视频翻译时长限制5分钟以内,需要积分2700首次有减免大概21.6元(1秒9积分/1元100积分) • 视频翻译配音工具pyvideotrans 将视频从一种语言翻译为另一种语言,并添加配音 打包链接:夸克网盘分享 升级补丁&#…

QT表格显示MYSQL数据库源码分析(七)

一. 连接MySQL数据库 首先,创建了一个QSqlDatabase对象,并设置数据库类型为"QMYSQL"。然后,它设置了数据库的主机名,端口号,数据库名,用户名和密码。最后,尝试打开数据库连接&#x…

GraphRAG的实践

好久没有体验新技术了,今天来玩一下GraphRAG 顾名思义,一种检索增强的方法,利用图谱来实现RAG 1.配置环境 conda create -n GraphRAG python3.11 conda activate GraphRAG pip install graphrag 2.构建GraphRAG mkdir -p ./ragtest/i…

MySQL通过bin-log恢复数据

MySQL通过bin-log恢复数据 1.bin-log说明2.数据恢复流程2.1 查看是否开启bin-log2.3 查看bin-log2.4 执行数据恢复操作2.5 检查数据是否恢复 1.bin-log说明 mysqldump和bin-log都可以作为MySQL数据库备份的方式: mysqldump 用于将整个或部分数据库导出为可执行的S…

周记-20240722

我现在写的周记已经不能称之为周记了,因为我太忙了,不知不觉整个6月都在忙,然后7月也在忙工作,6月下旬前期我感冒好了,过得还行,后来月底参加了单位的登山比赛,然后获得了名次,赢得了…

cms wpscan使用方式--kali linux

WPScan是一个用于WordPress安全审计和漏洞扫描的工具,可以通过以下命令来使用WPScan: 扫描一个网站: wpscan --url http://example.com扫描一个网站并指定用户名和密码: wpscan --url http://example.com --useradmin --passwo…

RoundCube搭建安装教程:服务器配置方法?

RoundCube搭建安装教程的疑问解析!怎么搭建邮件系统? RoundCube是一款开源的Web邮件客户端,具有现代化的用户界面和丰富的功能,可以通过浏览器访问邮件服务器。AokSend将详细介绍如何在服务器上配置和安装RoundCube,以…

【Linux】SYSCALL_DEFINE4 openat执行流程摸索

在上一篇博客,我们基于pr_info这个内核类似c语言printf打印宏完成了打印,基本实现了自由开关打印,可以设定打印日志次数(代码写了,大概10行代码),在测试的时候发现居然还有意外收获,…

物联网平台是干什么的用的

物联网平台是一个基于互联网技术和传感器技术,用于实现物联网应用开发、管理和运营的软件平台。以下是物联网平台的主要用途和功能,以及在一些领域的应用举例: 一、物联网平台的主要用途和功能 设备管理:物联网平台能够管理大量的…

嵌入式硬件-Xilinx FPGA DDR4 接口配置基础(PG150)

1. 简介 1.1 DDR4 SDRAM 控制器主要特点 支持8到80位接口宽度的组件(支持 RDIMM、LRDIMM、UDIMM 和 SODIMM) 最大组件限制为9,此限制仅适用于组件,不适用于 DIMM。密度支持 最高支持 32 GB 的组件密度,64 GB 的 LRDI…

Transformer图文详解【Attention is all you need】

NLP-大语言模型学习系列目录 一、注意力机制基础——RNN,Seq2Seq等基础知识 二、注意力机制【Self-Attention,自注意力模型】 三、Transformer图文详解【Attention is all you need】 文章目录 NLP-大语言模型学习系列目录一、Transformer框架二、Encoder(1&#x…

透彻理解Transformer模型:详解及实用示例(C#版)

随着自然语言处理(NLP)技术的发展,Transformer模型已经成为了许多现代NLP任务的基础。在这篇文章中,我们将深入解析Transformer模型的核心原理,并提供详细的C#代码示例,帮助您理解和实现这一强大的模型。 …

第十四届蓝桥杯省赛C++B组I题【景区导游】题解(AC)

解题思路 题目已给出地图为一个 n n n 个点, n − 1 n-1 n−1 条路线的树。 对于计算树中任意两点的距离,我们可以使用 LCA 算法进行快速计算。 假设 a , b a, b a,b 的最近公共祖先为 c c c,那么 a , b a,b a,b 之间的距离为 d i s …

太速科技-基于XCVU9P+ C6678的8T8R的无线MIMO平台

基于XCVU9P C6678的8T8R的无线MIMO平台 一、板卡概述 板卡基于TI TMS320C6678 DSP和XCVU9P高性能FPGA,FPGA接入4片AD9361 无线射频,构建8输入8输出的无线MIMO平台,丰富的FPGA资源和8核DSP为算法验证和信号处理提供强大能力。 二…

数据仓库中的数据治理方法

在数据仓库中,数据治理是确保数据质量和可信度的重要实践。数据治理方法涉及规划、执行和监控一系列活动,以保障数据的准确性、完整性和一致性。 一、数据清洗: 数据清洗是数据治理中的一项关键任务,用于检测和纠正数据中的错误…

python:本机摄像头目标检测实时推理(使用YOLOv8n模型)

本文将介绍如何使用本机摄像头进行目标检测实时推理的python代码。 文章目录 一、下载YOLO权重文件二、环境配置三、完整代码 一、下载YOLO权重文件 https://github.com/ultralytics/ultralytics?tabreadme-ov-file 拉到网页最下面,选择适合的模型,下…