linux网络重置报错,Linux网络编程中EAGAIN错误和EINTR错误
在Linux环境下开发经常会碰到很多错误(设置errno),其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中)。
从字面上来看,是提示再试一次。这个错误经常出现在当应用程序进行一些非阻塞(non-blocking)操作(对文件或socket)的时候。例如,以O_NONBLOCK的标志打开文件/socket/FIFO,如果你连续做read操作而没有数据可读。此时程序不会阻塞起来等待数据准备就绪返回,read函数会返回一个错误EAGAIN,提示你的应用程序现在没有数据可读请稍后再试。
又例如,当一个系统调用(比如fork)因为没有足够的资源(比如虚拟内存)而执行失败,返回EAGAIN提示其再调用一次(也许下次就能成功)。
Linux - 非阻塞socket编程处理EAGAIN错误
在linux进行非阻塞的socket接收数据时经常出现Resource temporarily
unavailable,errno代码为11(EAGAIN),这是什么意思?
这表明你在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不用管它,下次循环接着recv就可以。对非阻塞socket而言,EAGAIN不是一种错误。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。
EINTR错误:
慢系统调用(slow system
call):此术语适用于那些可能永远阻塞的系统调用。永远阻塞的系统调用是指调用有可能永远无法返回,多数网络支持函数都属于这一类。如:若没有客户连接到服务器上,那么服务器的accept调用就没有返回的保证。
EINTR错误的产生:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应信号处理函数返回时,该系统调用可能返回一个EINTR错误。例如:在socket服务器端,设置了信号捕获机制,有子进程,当在父进程阻塞于慢系统调用时由父进程捕获到了一个有效信号时,内核会致使accept返回一个EINTR错误(被中断的系统调用)。
当碰到EINTR错误的时候,可以采取有一些可以重启的系统调用要进行重启,而对于有一些系统调用是不能够重启的。例如:accept、read、write、select、和open之类的函数来说,是可以进行重启的。不过对于套接字编程中的connect函数我们是不能重启的,若connect函数返回一个EINTR错误的时候,我们不能再次调用它,否则将立即返回一个错误。针对connect不能重启的处理方法是,必须调用select来等待连接完成。
对于socket接口(指connect/send/recv/accept..等等后面不重复,不包括不能设置非阻塞的如select),在阻塞模式下有可能因为发生信号,返回EINTR错误,由用户做重试或终止。
但是,在非阻塞模式下,是否出现这种错误呢?
对此,重温了系统调用、信号、socket相关知识,得出结论是:不会出现。
首先,
1.信号的处理是在用户态下进行的,也就是必须等待一个系统调用执行完了才会执行进程的信号函数,所以就有了信号队列保存未执行的信号
2.用户态下被信号中断时,内核会记录中断地址,信号处理完后,如果进程没有退出则重回这个地址继续执行
socket接口是一个系统调用,也就是即使发生了信号也不会中断,必须等socket接口返回了,进程才能处理信号。
也就是,EINTR错误是socket接口主动抛出来的,不是内核抛的。socket接口也可以选择不返回,自己内部重试之类的..
那阻塞的时候socket接口是怎么处理发生信号的?
举例
socket接口,例如recv接口会做2件事情,
1.检查buffer是否有数据,有则复制清除返回
2.没有数据,则进入睡眠模式,当超时、数据到达、发生错误则唤醒进程处理
socket接口的实现都差不了太多,抽象说
1.资源是否立即可用,有则返回
2.没有,就等...
对于
1.这个时候不管有没信号,也不返回EINTR,只管执行自己的就可以了
2.采用睡眠来等待,发生信号的时候进程会被唤醒,socket接口唤醒后检查有无未处理的信号(signal_pending)会返回EINTR错误。
所以
socket接口并不是被信号中断,只是调用了睡眠,发生信号睡眠会被唤醒通知进程,然后socket接口选择主动退出,这样做可以避免一直阻塞在那里,有退出的机会。非阻塞时不会调用睡眠。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1、介绍慢系统调用
该术语适用于那些可能永远阻塞的系统调用。永远阻塞的系统调用是指调用永远无法返回,多数网络支持函数都属于这一类。如:若没有客户连接到服务器上,那么服务器的accept调用就会一直阻塞。
慢系统调用可以被永久阻塞,包括以下几个类别:
(1)读写‘慢’设备(包括pipe,终端设备,网络连接等)。读时,数据不存在,需要等待;写时,缓冲区满或其他原因,需要等待。读写磁盘文件一般不会阻塞。
(2)当打开某些特殊文件时,需要等待某些条件,才能打开。例如:打开中断设备时,需要等到连接设备的modem响应才能完成。
(3)pause和wait函数。pause函数使调用进程睡眠,直到捕获到一个信号。wait等待子进程终止。
(4)某些ioctl操作。
(5)某些IPC操作。
2、EINTR错误产生的原因
如果进程在一个慢系统调用(slow system
call)中阻塞时,当捕获到某个信号且相应信号处理函数返回时,这个系统调用被中断,调用返回错误,设置errno为EINTR(相应的错误描述为“Interrupted
system call”)。
如下表所示的系统调用就会产生EINTR错误,当然不同的函数意义也不同。
系统调用函数
errno为EINTR表征的意义
write
由于信号中断,没写成功任何数据。
The call was interrupted by a signal before any data was written.
open
由于信号中断,没读到任何数据。
The call was interrupted by a signal before any data was read.
recv
由于信号中断返回,没有任何数据可用。
The receive was interrupted by delivery of a signal before any data were available.
sem_wait
函数调用被信号处理函数中断。
The call was interrupted by a signal handler.
3、解决办法
既然系统调用会被中断,那么别忘了要处理被中断的系统调用。有三种处理方式:
1 人为重启被中断的系统调用
当碰到EINTR错误的时候,有一些可以重启的系统调用要进行重启,而对于有一些系统调用是不能够重启的。例如:accept、read、write、select、和open之类的函数来说,是可以进行重启的。不过对于套接字编程中的connect函数我们是不能重启的,若connect函数返回一个EINTR错误的时候,我们不能再次调用它,否则将立即返回一个错误。针对connect不能重启的处理方法是,必须调用select来等待连接完成。
理解“重启”?
一些IO系统调用执行时,如 read 等待输入期间,如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后,
系统遇到了一个问题: 是重新开始这个系统调用, 还是让系统调用失败?早期UNIX系统的做法是, 中断系统调用,并让系统调用失败,
比如read返回 -1, 同时设置 errno
为EINTR中断了的系统调用是没有完成的调用,它的失败是临时性的,如果再次调用则可能成功,这并不是真正的失败,所以要对这种情况进行处理,
典型的方式为如下,我们采用accept函数为例子,代码如下
ACCEPT:
clifd=accept(srvfd,(struct sockaddr*)&cliaddr,&cliaddrlen);
if (clifd== -1) {
if (errno== EINTR) {
goto ACCEPT;
} else {
fprintf(stderr, "accept fail,error:%s\n", strerror(errno));
return -1;
}
}
2 安装信号时设置 SA_RESTART属性(该方法对有的系统调用无效)
struct sigaction action;
action.sa_handler=handler_func;
sigemptyset(&action.sa_mask);
action.sa_flags=0;
action.sa_flags |= SA_RESTART;
sigaction(SIGALRM, &action, NULL);
并不是所有的都有效
3 忽略信号(让系统不产生信号中断)
struct sigaction action;
action.sa_handler=SIG_IGN;
sigemptyset(&action.sa_mask);
sigaction(SIGALRM, &action, NULL);
所以建议大家用第一种方法,重启。
linux网络重置报错,Linux网络编程中EAGAIN错误和EINTR错误相关推荐
- linux升级 nginx报错,Linux下升级nginx,编译安装nginx-sticky-module
添加一个nginx-sticky-module模块,可以防止session丢失,使用nginx sticky模块实现基于cookie的负载均衡. 注:建议去官网下载安装包 ${0}:安装包所在目录:$ ...
- linux编译curses报错,linux屏幕编程:curses库的使用
curses库是一组函数,可以用它来设置光标的位置和终端屏幕上显示的字符样式.curses库将终端屏幕看成是由字符单元组成的网格,每一个单元由(行.列)坐标对标示.坐标原点是屏幕的左上角,行坐标自上而 ...
- linux iso挂载报错,linux下文件系统、iso挂载
分类:Mount命令:需要注意的:1.挂载点必须是一个目录.2.一个分区挂载在一个已存在的目录上,这个目录可以不为空,但挂载后这个目录下以前的内容将不可用. 分类:Mount命令: 需要注意的: 1. ...
- linux系统安装软件报错,Linux安装软件时报错解决方法
提示 Could not get lock /var/lib/dpkg/lock 报错? 有些小伙伴在使用 apt 包管理器更新或安装软件时,可能会遇到过诸如以下的错误提示: E: Could not ...
- linux编译驱动报错,Linux编译声卡驱动
关于Linux编译声卡驱动: 惠普笔记本刚买来时,安装Debian 5,通常会遇到两个问题.一个是无线网卡驱动没有安装,一个是"带上耳机可以听歌,但是喇叭无法发声". 对于前面一个 ...
- linux修改用户名报错,Linux 用户切换、修改用户名、修改密码
一.用户切换 "$":普通用户提示符 "#":root用户提示符 1.普通用户到root: 方式一:命令:su然后输入root密码 此种方式只是切换了root身 ...
- linux切换root报错,Linux用户切换到root后运行图形程序报错(*GLib-GIO-CRITICAL **)
用su切换到root用户后,运行某些带图形的程序,会报如下错误: (ImageProc_qt:3158): GLib-GIO-CRITICAL **: g_dbus_connection_regist ...
- linux tomcat重启 报错,Linux启动Tomcat或停止Tomcat的错误解决方案
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 在tomcat中产生如下文件且报错: -rw-rw-r-- 1 17946 Feb 21 09:24 hs_err_pid20807.log -rw-rw ...
- linux开机内存报错,linux查看与修改交换内存配置(解决zabbix-agent启动报错)
问题 zabbix-agent在一台centos6.5上启动报错: cannot allocate shared memory of size 949056: [28] No space left o ...
最新文章
- 在IIS上搭建WebSocket服务器(一)
- hdu2846(2009多校第四场) 字典树
- Android 三方库EventBus的使用
- LuoGuP4721:【模板】分治 FFT
- iOS之深入解析缓存方法cache_t底层原理
- 计算机网络——TCP/IP参考模型和五层参考模型
- 如何实现ArcSDE的集群功能
- 微信从业人员推荐阅读的100本经典图书
- 数据分析笔试题(网易,阿里,京东...)
- 【Audio】WAV音频文件格式结构解析
- (01)f103,4pin四脚的 oled(01)
- Hexo的Next主题详细配置
- APEX弹窗闪退报错(005,006,007 DXGI_ERROR_DEVICE_REMOVED)问题完全解决方案
- 计算机网络的产生与发展可分为哪四个阶段,计算机网络形成与发展大致分为如下4个阶段...
- python使用UDP协议进行远程桌面共享
- 使用科大讯飞SDK实现语音功能
- JAVA实现QQ:实现文字聊天、QQ用户登录、拉取在线用户列表、无异常退出、私聊、发文件、下载文件、离线留言、服务端推送新闻等功能(后端无界面,Utilty源码在后面、)
- 电机FOC中的坐标变换(CLARK+PARK+公式推导+仿真+C语言实现)
- mysql停电_MySQL断电后报错处理
- JAVA在本地创建一个文件 向文件里面写入内容