Linux下调用socket的accept时,客户端强制断开 accept报错accept: Interrupted system call

在Ubuntu 16.04下,使用fork创建的多进程socket服务遇到问题,当客户端断开连接(无论是自动断开还是强制断开)时,服务器程序收到'accept: Interrupted system call'错误并异常结束。原因是信号处理函数打断了accept系统调用。通过修改信号集的sa_flags标志位,启用SA_RESTART,可以在信号处理后恢复系统调用,解决了该问题。代码已上传至GitHub,欢迎测试和指正。
摘要由CSDN通过智能技术生成

项目场景:

Ubunto16.04版下 使用fork创建多进程socket服务


问题描述:

在客户端断开连接后 不论是自动断开 开始ctrl+c强制断开 都会出现accept:Interrupted system cal 从而导致服务器程序异常结束


原因分析:

一开始是我怀疑是fork的原因 反复调整父子线程退出的逻辑还是不行 搜索报错信息发现大多数的答案都是要像下面这样写accept函数

if((connfd=accept(listenfd,NULL, NULL)) < 0) 
{
     if (errno == EINTR)
         continue;
     else
         printf("accept error");
} 

但是我觉得这样写很复杂 想搞清楚到底是什么原因

搜索到的相关问题大多数都引用了下面这句话

我们用术语慢系统调用(slow system call)描述accept函数,该术语也适用于那些可能永远阻塞的系统调用。永远阻塞的系统调用有可能永远无法返回,多数网络支持函数都属于这一类。举例来说,如果没有客户连接到服务器上,那么服务器的accept调用就没有返回的保证。类似的,如果客户端从未发送过数据,那么read调用将永不返回。其他慢系统调用的例子是对管道和终端设备的读和写。一个值得注意的例外是磁盘IO,它们一般都会返回到调用者(假设没有灾难性的硬件事故)。
适用于慢系统调用的基本规则是:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应处理函数返回时,该系统调用可能返回一个EINTR错误。所以,我们必须对慢系统调用返回的EINTR有所准备。

这应该是机翻的效果 感觉读起来很不清晰

但是我注意到系统调用这几个字 突然想起来在信号捕捉内容里有了解过大概的内容  其中有提到过一个对于信号回调函数的处理问题

在struct sigaction结构体变量中有一个sa_flags变量

在man命令下是这么解释sa_flags变量的

一般情况下我都将sa_flags置0 表示默认处理方式 但是有一个可选参数 内容如下

大概就是在信号回调函数打断了系统调用后 使用这个标志 可以重新启用系统调用 也就是前面的accept函数

 


解决方案:

修改信号集的标志位可以解决这个问题

struct sigaction act;  //创建信号集
act.sa_handler = reclaimChildProcess;  //指定回调函数
act.sa_flags = SA_RESTART;  //设置标志位
sigemptyset(&act.sa_mask);  //清空信号集

sigaction(SIGCHLD, &act, NULL);   //捕捉子进程结束信号

我也不太清楚到底是不是因为在回调函数中处理了子进程的回收才造成了accpet的异常退出 

从结果来看 执行完回调函数后 确实不会再因为客户端的退出而出现accep的异常报错

服务器的程序我上传到Github了 大家可以用自己写的客户端程序连接试试看 也可以用网络调试助手作为客户端连接

https://github.com/DDDoraemon/Fork_Socket.git

关于系统调用这方面我还不太了解 有清楚相关内容的大佬 如果我的解释有不对的地方 可以私信我修改文章 欢迎大家指出错误

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值