系统调用中断(EINTR)与SIGCHLD信号的处理

article/2025/10/16 0:43:31

      • 一、被中断的系统调用(EINTR)的理解
          • 1. 慢系统调用是?
          • 2. 慢系统调用的类别
          • 3. EINTR产生的原因
          • 5. 一般处理方法
      • 二、SIGCHLD信号的处理
          • 1. SIGCHLD信号的产生
          • 2. SIGCHLD信号的处理
          • 3. 不处理SIGCHLD的后果
      • 三、示例代码

一、被中断的系统调用(EINTR)的理解

1. 慢系统调用是?

慢系统调用指可能永远阻塞的系统调用。

也就是处于阻塞状态的系统调用,如果不收到需要的信息,就会一直阻塞在那里。例如accept:在服务器等待客户端建立连接时,如果没有客户端来请求连接,那么accept就会一直阻塞,直到有客户端请求连接为止。像这种系统调用,就称为慢系统调用。

2. 慢系统调用的类别
  • 对管道的读写
  • 对终端设备设备的读写
  • 对网络连接的读写
  • ……

值得注意的是,读写磁盘文件一般不会阻塞,一般会返回给调用者(在没有硬件故障的条件下)

3. EINTR产生的原因

当阻塞于某个慢系统调用的一个进程捕获某个信号且相应信号处理函数返回时,该系统调用可能返回一个EINTR错误。有些内核会自动重启某些被中断的系统调用。

对这句话的理解:
慢系统调用在阻塞状态中,如果收到了某个信号,该系统调用就会被中断,转而去执行对应的信号处理函数,在信号处理函数执行完后,被中断的系统调用就会返回EINTR。有的内核会在被中断的系统调用返回EINTR后重新执行。

accept为例,在服务器阻塞于accept时,这时之前已连接的客户端关闭了,对应该客户端的子进程就会退出,并发送SIGCHLD信号。如果定义了信号处理函数,就会造成accept的中断,然后执行该信号处理函数,执行完后accept就会返回EINTR

5. 一般处理方法

推荐将对accept的调用改为:

while( true ) {int clientlen = sizeof( cliaddr );int connfd = accept( sockfd, (struct sockaddr *)&cliaddr, &clietnlen );if( connfd < 0 ) {if( errnp == EINTR ) {  //如果返回EINTR,就重启该系统调用continue;} else {perror( "accept " );}}// do other things
}

还有两种方法:设置SA_RESTART属性、忽略信号,不过推荐使用上述方法。

二、SIGCHLD信号的处理

1. SIGCHLD信号的产生

在子进程退出时,会发送给父进程一个SIGCHLD信号来表明子进程已退出,此时可以使用wait/waitpid来等待子进程退出并回收子进程占用的资源,避免产生僵尸进程。该信号被默认为忽略。

2. SIGCHLD信号的处理

可以定义该信号的信号处理函数,并使用signal()来运行该信号对应的信号处理函数。

void sig_chld( int signo ) {pid_t pid;int stat;while( ( pid = waitpid( -1, &stat, WNOHANG ) ) > 0 ) {printf("child %d terminated\n", pid );}return ;
}signal( SIGCHLD, sig_chld );

其中,我们必须要为waitpid()函数设置WNOHANG属性,以便告知waitpid在仍有子进程尚未终止时不要阻塞。
循环中不能使用wait()函数,因为我们不能保证wait在还有子进程运行时不会发生阻塞。

在使用循环判断后,就可以将所有已结束的子进程的资源进行回收。

3. 不处理SIGCHLD的后果

如果我们在收到SIGCHLD信号后忽略,而且也没有在父进程最后wait/waitpid子进程结束,就会有僵尸进程产生。僵尸进程虽然不再占有内存等资源,但是会保留进程表中的表项,因此会造成内存泄漏。

linux下,可以使用ps命令查看,stat一栏标志为Z的就是僵尸进程。

三、示例代码

  • server.cpp
#include <iostream>
#include <string.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>
#include <wait.h>
using namespace std;const int PORT = 8080;/* 接收客户端信息 */
void str_echo( int conn_fd ) {ssize_t n;char buf[1024] = {0};while( ( n = read( conn_fd, buf, 1024 ) ) > 0 ) {write( conn_fd, buf, n );}if( n < 0 && errno == EINTR ) {continue;} else if( n < 0 ) {perror( "read " );}
}void sig_chld( int signo ) {pid_t pid;int stat;while( ( pid = waitpid( -1, &stat, WNOHANG ) ) > 0 ) {printf("child %d terminated\n", pid );}return ;
}int main() {int sock_fd = socket( AF_INET, SOCK_STREAM, 0 );if( sock_fd < 0 ) {perror( "socket " );}struct sockaddr_in servaddr;memset( &servaddr, 0, sizeof( servaddr ) );servaddr.sin_family = AF_INET;servaddr.sin_port = htons( PORT );servaddr.sin_addr.s_addr = htonl( INADDR_ANY );int ret = bind( sock_fd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) );if( ret < 0 ) {perror( "bind " );}ret = listen( sock_fd, 5 );if( ret < 0 ) {perror( "bind " );}signal( SIGCHLD, sig_chld );while( true ) {struct sockaddr_in clieaddr;socklen_t len;memset( &clieaddr, 0, sizeof( clieaddr ) );int conn_fd = accept( sock_fd, ( sockaddr * )&clieaddr, &len );if( conn_fd < 0 ) {if( errno == EINTR ) {cout << "EINTR\n";continue;} else {perror( "accept " );}}if( fork() == 0 ) {close( sock_fd );str_echo( conn_fd );exit(0);}close( conn_fd );}return 0;
}
  • client.cpp
#include <iostream>
#include <string.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;const int PORT = 8080;/* 给服务器发送、接收消息的函数 */
void str_cli( FILE *fp, int sock_fd ) {char recvline[1024] = {0}, sendline[1024] = {0};while( fgets( sendline, 1024, fp ) != NULL ) {write( sock_fd, sendline, strlen(sendline) );if( read( sock_fd, recvline, 1024 ) == 0 ) {perror( "readline " );}fputs( recvline, stdout );}
}int main( int argc, char **argv ) {if( argc != 2 ) {cout << "Usage : ./client + ip\n";return 0;}int sock_fd[5] = {0};for( int i = 0; i < 5; i++ ) {  // 创建5个连接sock_fd[i] = socket( AF_INET, SOCK_STREAM, 0 );if( sock_fd[i] < 0 ) {perror( "socket " );}sockaddr_in servaddr;memset( &servaddr, 0, sizeof( servaddr ) );servaddr.sin_family = AF_INET;servaddr.sin_port = htons( PORT );inet_pton( AF_INET, argv[1], &servaddr.sin_addr );int ret = connect( sock_fd[i], (sockaddr *)&servaddr, sizeof( servaddr ) );if( ret < 0 ) {perror( "connect " );}}str_cli( stdin, sock_fd[0] );return 0;
}

运行结果:
1


http://chatgpt.dhexx.cn/article/DxcgyUDD.shtml

相关文章

StringUtils 工具

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency>实验室&#xff1a; 常用方法&#xff1a; StringUtils.truncate("abcdefg", 7);StringUtils.wrapIfMissing("ab&…

StringUtils

今天我来谈一下Java里面一个工具类StringUtils&#xff0c;其实在Java里面一般把工具类写成静态的&#xff0c;这样是为了在使用的时候好调用。但是StringUtils这个类在Java API文档是没有的&#xff0c;所以必须要去倒StringUtils所属于的jar包。而StringUtils所属于的jar包是…

使用Python websockets搭建互联网服务器

在上一篇文章中实现局域网的通信&#xff0c;使用websockets,python作服务端&#xff0c;unity作客服端完成网络通信 这次准备实现互联网上的通信。 1.整个云服务器 要实现互联网通信&#xff0c;简单的方法就是先准备一个云服务器&#xff0c;这里我直接使用了阿里云服务器。…

【ZED2-3】python同时实现websockets与flask

上篇博客【ZED-2】基于WebSockets库&#xff0c;通过多线程方式推送数据流_WXG1011的博客-CSDN博客采用多线程方式&#xff0c;基于websockets库实现数据流的推送&#xff0c;这篇博客主要实现将前端&#xff08;nx板&#xff09;代码移植到flask框架中&#xff0c;通过http方式…

【burpsuite安全练兵场-客户端16】测试WebSockets安全漏洞-3个实验(全)

前言&#xff1a; 介绍&#xff1a; 博主&#xff1a;网络安全领域狂热爱好者&#xff08;承诺在CSDN永久无偿分享文章&#xff09;。 殊荣&#xff1a;CSDN网络安全领域优质创作者&#xff0c;2022年双十一业务安全保卫战-某厂第一名&#xff0c;某厂特邀数字业务安全研究员&…

在python中使用websockets

WebSocket (WebSocket) Websocket is a communications protocol, providing full-duplex bi-directional communication over a single TCP connection. Websocket是一种通信协议,可通过单个TCP连接提供全双工双向通信。 To understand Websockets, first, we have to have …

django3 websockets

一、概述 现在Django 3.0附带了对ASGI的支持&#xff0c;将Websockets添加到Django应用中不需要任何额外的依赖关系。 在本文中&#xff0c;您将学习如何通过扩展默认的ASGI应用程序来使用Django处理Websocket。 我们将介绍如何在示例ASGI应用程序中处理Websocket连接&#xff…

websockets_WebSockets简介

websockets WebSockets are an alternative to HTTP communication in Web Applications. WebSocket是Web应用程序中HTTP通信的替代方法。 They offer a long lived, bidirectional communication channel between client and server. 它们在客户端和服务器之间提供了长期的双…

尝试Python的websockets库的最基础功能

目标 尝试最简单的代码创建一个服务器并在客户端收发信息。 主要参考的是官方文档的首页&#xff1a;https://websockets.readthedocs.io/ &#xff08;还需要 asyncio 库的一些知识&#xff0c;可见之前的博客 翻译《使用asyncio的一个指南》作者&#xff1a;Andrew Crozier…

python使用websockets库

python使用websockets库 serve:在server端使用&#xff0c;等待客户端的连接。如果连接成功&#xff0c;返回一个websocket。 connect: 在client端使用&#xff0c;用于建立连接。 send:发送数据 recv:接收数据 close:关闭连接 服务端 #!/usr/bin/python3 # 主要功能&am…

什么是WebSockets!?

到目前为止&#xff0c;我们已经深入到实时世界&#xff0c;因为许多应用程序使用实时数据。 现在正是以技术立场解释所有导致这一点的事件的时候了。 所以&#xff0c;这里...... 目前&#xff0c;应用程序正在从利用数据库中的陈旧数据或在实际事件之后的实时体验中事…

WebSockets介绍

Web sockets定义为在servers和clients之间的双向连接。意味着servers和clients可以同时交流并发送数据。这种协议是从底层就是双工连接。Web sockets技术上得到了质的飞跃。 握手是一个过程&#xff0c;确保server与client同步。握手是Web Socket protocol的基础概念。 下面的图…

websockets_将WebSockets与Node.js结合使用

websockets WebSockets are an alternative to HTTP communication in Web Applications. WebSocket是Web应用程序中HTTP通信的替代方法。 They offer a long lived, bidirectional communication channel between client and server. 它们在客户端和服务器之间提供了长期的双…

各大公司数据结构与算法面试题解答(一)

还有一年就要找工作了&#xff0c;从现在开始找些公司的数据结构和算法的题来做一做&#xff0c;不定时贴出笔试面试题代码。 1.创新工场&#xff1a; 求一个数组的最长递减子序列比如{9&#xff0c;4&#xff0c;3&#xff0c;2&#xff0c;5&#xff0c;4&#xff0c;3&…

数据结构面试题整理

一 数据结构 1.你熟悉什么数据结构&#xff1f; 数组 链表 栈 队列 哈希 二叉树 二叉查找树 二叉堆 b树 b树 2.b树 b树 b*树 b和b都是节点可以有很多子节点&#xff0c;区别是b树所有的节点都可以存储关键字&#xff0c;而b树只有叶子节点存储关键字&#xff0c;适用于数据库…

数据结构与算法三十题,弄懂这些面试就够了!

https://www.toutiao.com/a6649963989537128967/ 2019-01-24 15:36:35 国外 IT 教育学院 Educative.io 创始人 Fahim ul Haq 写过一篇过万赞的文章《The top data structures you should know for your next coding interview》,总结了程序员面试中需要掌握的 8 种数据结构知识…

数据结构与算法面试知识点汇总(超全)

文章目录 一、哈希函数和哈希表01 哈希函数02 哈希表 二、布隆过滤器三、一致性哈希四、并查集01 具体实现02 优化03 代码实现 五、前缀树&#xff08;trie树&#xff09;六、B树和B树七、线段树01 线段树的优势02 线段树实现 一、哈希函数和哈希表 01 哈希函数 哈希函数&…

《数据结构》十道链表经典面试题多种方法深度解析

目录 ⛰️一、题目解析 &#x1f5fb;1.1删除链表中等于给定值 val 的所有节点&#xff08;力扣&#xff09; &#x1f5fb;1.2反转一个单链表。&#xff08;力扣&#xff09; &#x1f5fb;1.3给定一个带有头结点 head 的非空单链表&#xff0c;返回链表的中间结点。如果有…

数据结构和算法常见面试问题总结,含答案

0. 写在前面 总导航在此 这些问题是我备考数据结构和算法的过程中&#xff0c;详细总结的常见面试问题和答案。逐个搜索并记录下来&#xff0c;花了很大的精力&#xff01;如果想要获取源文件的话&#xff0c;可以关注我的微信公众号&#xff1a;小梁说代码&#xff0c;获取嘿…

(六)数据结构面试必问

什么是链表、队列、栈&#xff1f; 链表&#xff1a; 当需要存储多个相同数据类型的时候&#xff0c;可以使用数组存储&#xff0c;数组可以通过下标直接访问&#xff0c;但数组有个缺点就是无法动态的插入或删除其中的元素&#xff08;特别是操作第一个位置上的元素&#xff…