您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

从 Linux 源码看 Socket 的阻塞和非阻塞

时间:2021-04-29 10:08:33  来源:今日头条  作者:Linux后端开发
从 Linux 源码看 Socket 的阻塞和非阻塞

 

笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情。

大部分高性能网络框架采用的是非阻塞模式。笔者这次就从linux源码的角度来阐述socket阻塞(block)和非阻塞(non_block)的区别。 本文源码均来自采用Linux-2.6.24内核版本。

TCP 非阻塞 client 端的例子

如果我们要产生一个非阻塞的socket,在C语言中如下代码所示:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

由于网络协议非常复杂,内核里面用到了大量的面向对象的技巧,所以我们从创建连接开始,一步一步追述到最后代码的调用点。

socket 的创建

很明显,内核的第一步应该是通过AF_INET、SOCK_STREAM以及最后一个参数0定位到需要创建一个TCP的socket,如下图绿线所示:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

我们跟踪源码调用

 

从 Linux 源码看 Socket 的阻塞和非阻塞

 

进一步分析__sock_create的代码判断:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

由于family是AF_INET协议,注意在操作系统里面定义了PF_INET等于AF_INET, 内核通过函数指针实现了对pf(net_proto_family)的重载。如下图所示:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

则通过源码可知,由于是AF_INET(PF_INET),所以net_families[PF_INET].create=inet_create(以后我们都用PF_INET表示),即
pf->create = inet_create; 进一步追溯调用:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

上面的代码就是在INET中寻找SOCK_STREAM的过程了 我们再看一下inetsw[SOCK_STREAM]的具体配置:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

这边也用了重载,AF_INET有TCP、UDP以及Raw三种:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

从上述代码,我们可以清楚的发现sock->ops=&inet_stream_ops;

从 Linux 源码看 Socket 的阻塞和非阻塞

 

即sock->ops->recvmsg = sock_common_recvmsg;
同时sock->sk->sk_prot = tcp_prot;

我们再看下tcp_prot中的各个函数重载的定义:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

fcntl控制socket的阻塞非阻塞状态

我们用fcntl修改socket的阻塞非阻塞状态。 事实上: fcntl的作用就是将O_NONBLOCK标志位存储在sock_fd对应的filp结构的f_lags里,如下图所示。

从 Linux 源码看 Socket 的阻塞和非阻塞

 


从 Linux 源码看 Socket 的阻塞和非阻塞

 

追踪setfl代码:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

上图中,由sock_fd在task_struct(进程结构体)->files_struct->fd_array中找到对应的socket的file描述符,再修改file->flags

在调用socket.recv的时候

我们跟踪源码调用:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

由上文可知: sock->ops->recvmsg = sock_common_recvmsg;

  • sock

值得注意的是,在sock_recmsg中,有对标识O_NONBLOCK的处理

从 Linux 源码看 Socket 的阻塞和非阻塞

 

上述代码中sock关联的file中获取其f_flags,如果flags有O_NONBLOCK标识,那么就设置msg_flags为MSG_DONTWAIT(不等待)。
fcntl与socket就是通过其共同操作File结构关联起来的。

  • 继续跟踪调用

sock_common_recvmsg

从 Linux 源码看 Socket 的阻塞和非阻塞

 

由上文可知: sk->sk_prot->recvmsg 其中sk_prot=tcp_prot,即最终调用的是tcp_prot->tcp_recvmsg,上面的代码可以看出,如果fcntl(O_NONBLOCK)=>MSG_DONTWAIT置位=>(flags & MSG_DONTWAIT)>0, 再结合tcp_recvmsg的函数签名,即如果设置了O_NONBLOCK的话,设置给tcp_recvmsg的nonblock参数>0,关系如下图所示:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

  • 最终的调用逻辑tcp_recvmsg

首先我们看下tcp_recvmsg的函数签名:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

显然我们关注焦点在(int nonblock这个参数上):

从 Linux 源码看 Socket 的阻塞和非阻塞

 

上面的逻辑归结起来就是:
(1)在设置了nonblock的时候,如果copied>0,则返回读了多少字节,如果copied=0,则返回-EAGAIN,提示应用重复调用。
(2)如果没有设置nonblock,如果读取的数据>=期望,则返回读取了多少字节。如果没有则用sk_wait_data将当前进程等待。

如下流程图所示:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

  • 阻塞函数sk_wait_data

sk_wait_data代码-函数为:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

该函数调用schedule_timeout进入睡眠,其进一步调用了schedule函数,首先从运行队列删除,其次加入到等待队列,最后调用和体系结构相关的switch_to宏来完成进程间的切换。


如下图所示:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

  • 阻塞后什么时候恢复运行呢

情况1:有对应的网络数据到来

首先我们看下网络分组到来的内核路径,网卡发起中断后调用netif_rx将事件挂入CPU的等待队列,并唤起软中断(soft_irq),再通过linux的软中断机制调用net_rx_action,如下图所示:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

:上图来自PLKA(<<深入Linux内核架构>>)


紧接着跟踪next_rx_action

从 Linux 源码看 Socket 的阻塞和非阻塞

 

紧接着tcp_v4_rcv:

从 Linux 源码看 Socket 的阻塞和非阻塞

 

在这里__wake_up_common将停在当前wait_queue_head_t中的进程唤醒,即状态改为task_running,等待CFS调度以进行下一步的动作,如下图所示。

从 Linux 源码看 Socket 的阻塞和非阻塞

 

情况2:设定的超时时间到来

在前面调用sk_wait_event中调用了schedule_timeout

从 Linux 源码看 Socket 的阻塞和非阻塞

 

process_timeout函数即是将此进程重新唤醒

从 Linux 源码看 Socket 的阻塞和非阻塞

 

原文链接:
https://my.oschina.net/alchemystar/blog/1791017



Tags:Socket   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
一、背景在日常工作中我们经常会使用到代理, 这里记录一下Proxifier和ss5的使用,这两个工具既可以单独使用,也可以配合使用。本文讲解proxifier+ss5配合使用的场景及配置。 二...【详细内容】
2021-11-05  Tags: Socket  点击:(37)  评论:(0)  加入收藏
当初写第一个网络程序的时候,就是通过搜索,找各种实例把程序拼凑出来的,并没有进行深入的理解。这个东西用了这么多年,是该来沉淀一下了,也检验一下自己对这块知识的掌握程度。可...【详细内容】
2021-10-18  Tags: Socket  点击:(57)  评论:(0)  加入收藏
最近工作中需要开发前端操作远程虚拟机的功能,简称 WebShell。基于当前的技术栈为 react+django,调研了一会发现大部分的后端实现都是 django+channels 来实现 websocket 服务。...【详细内容】
2021-09-13  Tags: Socket  点击:(52)  评论:(0)  加入收藏
socket用listen函数监听,listen从英语上理解就是一个"听"函数,实际上它也就是这个意思。我们来看unix网络编程这本书是怎样对它的解释:listen函数把一个未连接的套接字转换成一...【详细内容】
2021-08-13  Tags: Socket  点击:(75)  评论:(0)  加入收藏
TCP客户端:1.建立连接套接字,设置Ip和端口监听,socket()2.建立连接 connect3.write() 获取网络流量对象 发送数据4.read()获取网络流量对象 接收数据5.关闭套接字 TCP服务器端1...【详细内容】
2021-07-08  Tags: Socket  点击:(144)  评论:(0)  加入收藏
我是笑林新记,分享一下我使用C#的一些用法,希望对大家有帮助!欢迎关注:笑林新记Visual Studio版本:Enterprise 2015.net Framework版本:3.51Socket介绍 有粉丝私信说让讲一下局域...【详细内容】
2021-06-28  Tags: Socket  点击:(159)  评论:(0)  加入收藏
前言:作为一个刚踏入职场的实习生,我很幸运参加了某个政府项目,并且在项目中负责一个核心模块功能的开发,而不是从头到尾对数据库的crud。虽然我一直心里抱怨我的工作范围根本...【详细内容】
2021-05-24  Tags: Socket  点击:(230)  评论:(0)  加入收藏
笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情。大部分高性能网络框架采用的是非阻塞模式。笔者这次就从linux源码的角度来阐述socket...【详细内容】
2021-04-29  Tags: Socket  点击:(266)  评论:(0)  加入收藏
有时候,由于业务的复杂性,在JVM中拼装一些数据,会造成资源的极大浪费。举个例子,从MySQL中查询出一个List,然后在代码里循环查询数据库,进行一些字段的填充。这种数据组装方式,除了...【详细内容】
2021-03-24  Tags: Socket  点击:(305)  评论:(0)  加入收藏
1)通知功能:保持一个长连接,当服务端游新的消息,能够实时的推送到使用方。像知乎的点赞通知、评论等,都可以使用WebSocket通信。某些使用H5的客户端,为了简化开发,也会使用WebSocke...【详细内容】
2021-03-03  Tags: Socket  点击:(156)  评论:(0)  加入收藏
▌简易百科推荐
摘 要 (OF作品展示)OF之前介绍了用python实现数据可视化、数据分析及一些小项目,但基本都是后端的知识。想要做一个好看的可视化大屏,我们还要学一些前端的知识(vue),网上有很多比...【详细内容】
2021-12-27  项目与数据管理    Tags:Vue   点击:(1)  评论:(0)  加入收藏
程序是如何被执行的&emsp;&emsp;程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  IT学习日记    Tags:程序   点击:(9)  评论:(0)  加入收藏
阅读收获✔️1. 了解单点登录实现原理✔️2. 掌握快速使用xxl-sso接入单点登录功能一、早期的多系统登录解决方案 单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器...【详细内容】
2021-12-23  程序yuan    Tags:单点登录(   点击:(8)  评论:(0)  加入收藏
下载Eclipse RCP IDE如果你电脑上还没有安装Eclipse,那么请到这里下载对应版本的软件进行安装。具体的安装步骤就不在这赘述了。创建第一个标准Eclipse RCP应用(总共分为六步)1...【详细内容】
2021-12-22  阿福ChrisYuan    Tags:RCP应用   点击:(7)  评论:(0)  加入收藏
今天想简单聊一聊 Token 的 Value Capture,就是币的价值问题。首先说明啊,这个话题包含的内容非常之光,Token 的经济学设计也可以包含诸多问题,所以几乎不可能把这个问题说的清...【详细内容】
2021-12-21  唐少华TSH    Tags:Token   点击:(9)  评论:(0)  加入收藏
实现效果:假如有10条数据,分组展示,默认在当前页面展示4个,点击换一批,从第5个开始继续展示,到最后一组,再重新返回到第一组 data() { return { qList: [], //处理后...【详细内容】
2021-12-17  Mason程    Tags:VUE   点击:(14)  评论:(0)  加入收藏
什么是性能调优?(what) 为什么需要性能调优?(why) 什么时候需要性能调优?(when) 什么地方需要性能调优?(where) 什么时候来进行性能调优?(who) 怎么样进行性能调优?(How) 硬件配...【详细内容】
2021-12-16  软件测试小p    Tags:性能调优   点击:(19)  评论:(0)  加入收藏
Tasker 是一款适用于 Android 设备的高级自动化应用,它可以通过脚本让重复性的操作自动运行,提高效率。 不知道从哪里听说的抖音 app 会导致 OLED 屏幕烧屏。于是就现学现卖,自...【详细内容】
2021-12-15  ITBang    Tags:抖音防烧屏   点击:(23)  评论:(0)  加入收藏
11 月 23 日,Rust Moderation Team(审核团队)在 GitHub 上发布了辞职公告,即刻生效。根据公告,审核团队集体辞职是为了抗议 Rust 核心团队(Core team)在执行社区行为准则和标准上...【详细内容】
2021-12-15  InfoQ    Tags:Rust   点击:(24)  评论:(0)  加入收藏
一个项目的大部分API,测试用例在参数和参数值等信息会有很多相似的地方。我们可以复制API,复制用例来快速生成,然后做细微调整既可以满足我们的测试需求1.复制API:在菜单发布单...【详细内容】
2021-12-14  AutoMeter    Tags:AutoMeter   点击:(20)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条