深入理解Linux网络(五):TCP接收唤醒

news2025/1/9 2:21:06

深入理解Linux网络(五):TCP接收唤醒

TCP接收唤醒由软中断提供服务。
在这里插入图片描述

软中断(也就是 Linux ⾥的 ksoftirqd 进程)⾥收到数据包以后,发现是 tcp 的包的话就会执⾏到 tcp_v4_rcv 函数。接着如果是 ESTABLISH 状态下的数据包,则最终会把数据拆出来放到对应 socket 的接收队列中。然后调⽤ sk_data_ready 来唤醒⽤户进程。

// file: net/ipv4/tcp_ipv4.c
int tcp_v4_rcv(struct sk_buff *skb)
{
 ......
 th = tcp_hdr(skb); //获取tcp header
 iph = ip_hdr(skb); //获取ip header
 //根据数据包 header 中的 ip、端⼝信息查找到对应的socket
 sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
 ......
 //socket 未被⽤户锁定
 if (!sock_owned_by_user(sk)) {
 {
  if (!tcp_prequeue(sk, skb))
  ret = tcp_v4_do_rcv(sk, skb);
 }
 }
}

在 tcp_v4_rcv 中⾸先根据收到的⽹络包的 header ⾥的 source 和 dest 信息来在本机上查询对应的 socket。找到以后,我们直接进⼊接收的主体函数 tcp_v4_do_rcv 来看。

//file: net/ipv4/tcp_ipv4.c
int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
{
 if (sk->sk_state == TCP_ESTABLISHED) {
 //执⾏连接状态下的数据处理
 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
 rsk = sk;
 goto reset;
 }
 return 0;
 }
 //其它⾮ ESTABLISH 状态的数据包处理
 ......
}

我们假设处理的是 ESTABLISH 状态下的包,这样就⼜进⼊ tcp_rcv_established 函数中进⾏处理。

//file: net/ipv4/tcp_input.c
int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
 const struct tcphdr *th, unsigned int len)
{
 ......
 //接收数据到队列中
 eaten = tcp_queue_rcv(sk, skb, tcp_header_len,
 &fragstolen);
 //数据 ready,唤醒 socket 上阻塞掉的进程
 sk->sk_data_ready(sk, 0);

在 tcp_rcv_established 中通过调⽤ tcp_queue_rcv 函数中完成了将接收数据放到 socket 的接收队列上。
在这里插入图片描述

//file: net/ipv4/tcp_input.c
static int __must_check tcp_queue_rcv(struct sock *sk, struct
  sk_buff *skb, int hdrlen, bool *fragstolen)
{
 //把接收到的数据放到 socket 的接收队列的尾部
 if (!eaten) {
   __skb_queue_tail(&sk->sk_receive_queue, skb);
   skb_set_owner_r(skb, sk);
 }
 return eaten;
}

调⽤ tcp_queue_rcv 接收完成之后,接着再调⽤ sk_data_ready 来唤醒在socket上等待的⽤户进程
这⼜是⼀个函数指针。 回想上⾯我们在 创建 socket 流程⾥执⾏到的 sock_init_data 函数,在这个函数⾥已经把 sk_data_ready 设置成 sock_def_readable 函数了。它是默认的数据就绪处理函数。

//file: net/core/sock.c
static void sock_def_readable(struct sock *sk, int len)
{
 struct socket_wq *wq;
 rcu_read_lock();
 wq = rcu_dereference(sk->sk_wq);
 //有进程在此 socket 的等待队列
 if (wq_has_sleeper(wq))
   //唤醒等待队列上的进程
   wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLPRI| POLLRDNORM | POLLRDBAND);
 sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
 rcu_read_unlock();
}

在 sock_def_readable 中再⼀次访问到了 sock->sk_wq 下的wait。回忆下我们前⾯调⽤ recvfrom 执⾏的最后,通过 DEFINE_WAIT(wait) 将当前进程关联的等待队列添加到 sock->sk_wq 下的 wait ⾥了。
那接下来就是调⽤ wake_up_interruptible_sync_poll 来唤醒在 socket 上因为等待数据⽽被阻塞掉的进程了。
在这里插入图片描述

//file: include/linux/wait.h
#define wake_up_interruptible_sync_poll(x, m) \
 __wake_up_sync_key((x), TASK_INTERRUPTIBLE, 1, (void *) (m))

//file: kernel/sched/core.c
void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, void *key)
{
 unsigned long flags;
 int wake_flags = WF_SYNC;
 if (unlikely(!q))
  return;
 if (unlikely(!nr_exclusive))
  wake_flags = 0;
  
 spin_lock_irqsave(&q->lock, flags);
 __wake_up_common(q, mode, nr_exclusive, wake_flags, key);
 spin_unlock_irqrestore(&q->lock, flags);
}

__wake_up_common 实现唤醒。这⾥注意下, 该函数调⽤是参数 nr_exclusive 传⼊的是 1,这⾥指的是即使是有多个进程都阻塞在同⼀个 socket 上,也只唤醒 1 个进程。其作⽤是为了避免惊群

//file: kernel/sched/core.c
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
 int nr_exclusive, int wake_flags, void *key)
{
 wait_queue_t *curr, *next;
 list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
   unsigned flags = curr->flags;
   if (curr->func(curr, mode, wake_flags, key) &&
     (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
     break;
 }
}

在 __wake_up_common 中找出⼀个等待队列项 curr,然后调⽤其 curr->func。在 recv 函数执⾏的时候,使⽤ DEFINE_WAIT() 定义等待队列项的细节,内核把 curr->func 设置成了 autoremove_wake_function。

//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), \
 }

autoremove_wake_function 又调⽤了 default_wake_function。

//file: kernel/sched/core.c
int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags, void *key)
{
 return try_to_wake_up(curr->private, mode, wake_flags);
}

调⽤ try_to_wake_up 时传⼊的 task_struct 是 curr->private。这个就是当时因为等待⽽被阻塞的进程项。 当这个函数执⾏完的时候,在 socket 上等待⽽被阻塞的进程就被推⼊到可运⾏队列⾥了,这⼜将是⼀次进程上下⽂切换的开销。

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

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

相关文章

GMSSL2.x编译鸿蒙静态库和动态库及使用

一、编译环境准备 1.1 开发工具 DevEco-Studio下载。 1.2 SDK下载 ​ 下载编译第三方库的SDK有两种方式,第一种方式从官方渠道根据电脑系统选择对应的SDK版本,第二种方式通过DevEco-Studio下载SDK。本文只介绍通过DevEco-Studio下载SDK的方式。 安装…

(十一)Spring教程——Bean基本配置与依赖注入之属性注入

1.Bean基本配置 在进行Bean配置的详细讲解之前&#xff0c;先来了解以下Bean配置的基础知识&#xff0c;以快速建立起Bean配置的初步概念。 1.1装配一个Bean 在Spring容器的配置文件中定义一个简要Bean的配置片段如下所示 <bean id”foo” class”com.smart.Foo”/> 一般…

【VSCode】安装 【ESP-IDF】插件及【ESP32-S3】新建工程和工程配置

一、搭建基础工程 二、基础工程的文件架构解析 三、调试相关工具介绍 1、串口下载2、JTAG 下载与调试 四、工程的文件架构解析 五、基础工程配置 一、搭建基础工程 在 VS Code 中新建 ESP-IDF 基础工程的步骤如下&#xff1a; 1、启动 VS Code 并打开命令面板 按下“Ctrl…

AI+BI结合,数据分析新方向 —— 奥威BI数据可视化引领未来

【AIBI结合&#xff0c;数据分析新方向 —— 奥威BI数据可视化引领未来】 在数字化浪潮汹涌的今天&#xff0c;企业对于数据的洞察力与决策效率的需求日益增长。奥威BI&#xff08;Business Intelligence&#xff09;数据可视化解决方案&#xff0c;以其独特的“AIBI”融合创新…

压缩视频在线免费 怎么免费压缩视频大小 哪个软件可以免费压缩视频

在数字媒体时代&#xff0c;视频文件的体积越来越大&#xff0c;这就需要我们找到高效的方式来压缩视频&#xff0c;以节省存储空间和提升分享速度。本文将为您介绍几款免费的视频压缩软件&#xff0c;帮助您轻松应对视频文件管理难题。 方法一、 安装并打开一款的视频软件。 …

通过iframe嵌套的不同域名的页面之间处理cookie存储失败的问题——js技能提升

最近同事在写mvc的后台管理系统&#xff0c;通过iframe实现不同域名的页面的嵌套。 但是有个问题&#xff0c;就是从父页面打开iframe的子页面时&#xff0c;需要登录子页面&#xff0c;此时需要将子页面登录后的token存储到子页面的cookie中&#xff0c;方便子页面的其他接口…

Python 全栈体系【三阶】(三)

第一章 Django 七、静态文件 1. 概述 静态文件是指在WEB应用中的图像文件、CSS文件、Javascript文件。 2. 静态文件的配置 settings.py中关于静态文件的配置如下&#xff1a; STATICFILES_DIRS [BASE_DIR , static, ]STATIC_URL /static/其中&#xff1a; STATICFILES…

Vue 3 + Vite 项目中安装 Tailwind CSS

官网&#xff1a;安装 - TailwindCSS中文文档 | TailwindCSS中文网 tips&#xff1a;只按照官网的配置可能会导致样式不加载/加载不生效的问题 1、正确安装指令 npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p 自动生成 ​tailwind.config.js​…

鱼眼摄像头-opencv校准(基于棋盘+畸变表)

一&#xff1a;主要参数说明 1&#xff1a;内参矩阵K 是3*3的矩阵&#xff0c;其类似格式 Knp.array([ [389.2109574522624, 0.0, 630.2525667489842], [0.0, 388.505701978078, 360.7886749292513], [0.0, 0.0, 1.0]]) 2&#xff1a;畸变系数 针对鱼眼相机&#xff1a;…

DVWA靶场超(详细教程)--跨站攻击(XSS+CSRF)

一、XSS 反射型xss 打开dvwa的Reflected Cross Site Scripting (XSS) &#xff08;1&#xff09;low等级 查看页面源码&#xff08;ctrlu&#xff09;该界面有提交按钮和输入框 在输入框随便输入点字符&#xff0c;点击提交 可以看见输入的helloword嵌入到界面中。 View sou…

MybatisPlus的使用与详细讲解

今天我们来讲解一下Mybatis的升级版&#xff0c;就是MybatisPlus. MybatisPlus是如何获取实现CRUD的数据库表信息的&#xff1f; 默认以类名驼峰转下划线作为表名 默认把名为id的字段作为主键 默认把变量名驼峰转下划线作为表的字段名 1.MybatisPlus中比较常见的注解 TableN…

红人点集登录逆向+接口逆向:SHA256算法和Webpack反爬

&#x1f50d; 引言 红人点集采取了一系列加密和限制措施&#xff0c;主要是对于参数加密和登录token加密。今天利用Python与JavaScript逆向工程技术&#xff0c;实现逆向登录然后请求接口获取数据。 &#x1f50d; 思路与步骤详解 &#x1f527; 解密登录接口参数&#xf…

安防视频监控EasyCVR视频汇聚平台修改配置后无法启动的原因排查与解决

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台基于云边端一体化架构&#xff0c;兼容性强、支持多协议接入&#xff0c;包括国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SD…

【Echarts示例】类甘特图的时间线图表

[示例] 类甘特图的时间线图表 const data [{ name: 预备阶段, start: 0, end: 2 },{ name: 战略展开, start: 2, end: 4 },{ name: 指挥所启动, start: 4, end: 6 },{ name: 电子对抗准备, start: 5.5, end: 7 },{ name: 首轮导弹发射, start: 7, end: 8.5 },{ name: 电子对抗…

Spark内核的设计原理

导读&#xff1a; 本期是DataFun深入浅出Apache Spark第一期的分享&#xff0c;主讲老师耿嘉安开场介绍了自己的从业经历&#xff0c;当前就职的数新网络与Spark相关的两款产品赛博数智引擎CyberEngine和赛博数据智能平台CyberData。 本次分享题目为《Spark内核的设计原理》&…

【测开能力提升-fastapi框架】fastapi能力提升 - 中间件与CORS

1. 中间件 1.1 介绍&#xff08;ChatGPT抄的&#xff0c;大致可以理解&#xff09; 一种机制&#xff0c;用于在处理请求和响应之前对其进行拦截、处理或修改。中间件可以在应用程序的请求处理管道中插入自定义逻辑&#xff0c;以实现一些通用的功能&#xff0c;如身份验证、…

系统架构设计师教程 第3章 信息系统基础知识-3.8 典型信息系统架构模型-解读

系统架构设计师教程 第3章 信息系统基础知识-3.8 典型信息系统架构模型-解读 3.8.1 政府信息化与电子政务3.8.1.1 电子政务的概念3.8.1.2 电子政务的内容3.8.1.2.1 政府与政府3.8.1.2.2 政府对企/事业单位3.8.1.2.3 政府对居民3.8.1.2.4 企业对政府3.8.1.2.5 居民对政府 3.8.1…

第一弹:基于ABAP OLE技术实现对服务器文件进行读写操作

前言 最近遇到这样一个需求&#xff0c;需要对BW服务器上的文件进行下载的同时写入每个用户相对应的数据。之前的服务器模版是一个死模版&#xff0c;对于这样的要求&#xff0c;我就想到了OLE技术&#xff0c;那么什么是OLE技术呢&#xff1f; 一、什么是OLE技术&#xff1f…

创建最佳实践创建 XML 站点地图--SEO

您是否正在努力让您的网站被搜索引擎索引&#xff1f;您想提高您网站的搜索引擎知名度吗&#xff1f;如果是&#xff0c;您可能会错过 XML 站点地图的重要性。XML 站点地图在改善您网站的 SEO 方面发挥着至关重要的作用。‍ XML 站点地图是您网站结构的蓝图&#xff0c;可帮助…

基于DPUSmartNic的云原生SDN解决方案

1. 方案背景与挑战 随着云计算&#xff0c;大数据和人工智能等技术的蓬勃发展&#xff0c;数据中心面临着前所未有的数据洪流和计算压力&#xff0c;这对SDN提出了更高的性能和效率要求。自云原生概念被提出以来&#xff0c;Kubernetes为云原生应用的落地提供了一个轻量级&am…