linux系统中socket错误码:eintr和eagain的处理方法( 二 )


如:首先是把套接字设置为异步的了 , 然后在使用write发送数据时采取的方式是循环发送大量的数据;由于是异步的 , writesend将要发送的数据提交到发送缓冲区后是立即返回的 , 并不需要对端确认数据已接收 。在这种情况下是很有可能出现发送缓冲区被填满 , 导致writesend无法再向缓冲区提交要发送的数据 。因此就产生了Resource temporarily unavailable的错误(资源暂时不可用) , 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 。
iReadSizeOnce=read(iOpenCom,RxBuf+iReadSize,1024);if (iReadSizeOnce != ZERO){if (iReadSizeOnce != EAGAIN){continue;}else{//stCComApiLog.LogError("读串口操作错误");return(FUN_ERROR);}}慢系统调用:可能永远阻塞的系统调用 , 这很关键 , 不适用于非诸塞的情况 。永远阻塞的系统调用是指调用永远无法返回 , 多数网络支持函数都属于这一类 。如:若没有客户连接到服务器上 , 那么服务器的accept调用就会一直阻塞 。
EINTR说明:如果进程在一个慢系统调用(slow system call)中阻塞时 , 当捕获到某个信号且相应信号处理函数返回时 , 这个系统调用被中断 , 调用返回错误 , 设置errno为EINTR(相应的错误描述为“Interrupted system call”) 。
怎么看哪些系统条用会产生EINTR错误呢?man 7 signal , 在ubuntu 10.04上可以查看 , 哪些系统调用会产生 EINTR错误 。
如何处理被中断的系统调用
既然系统调用会被中断 , 那么别忘了要处理被中断的系统调用 。有三种处理方式:
◆ 人为重启被中断的系统调用
◆ 安装信号时设置 SA_RESTART属性(该方法对有的系统调用无效)
◆ 忽略信号(让系统不产生信号中断)
人为重启被中断的系统调用
人为当碰到EINTR错误的时候 , 有一些可以重启的系统调用要进行重启 , 而对于有一些系统调用是不能够重启的 。例如:accept、read、write、select、和open之类的函数来说 , 是可以进行重启的 。不过对于套接字编程中的connect函数我们是不能重启的 , 若connect函数返回一个EINTR错误的时候 , 我们不能再次调用它 , 否则将立即返回一个错误 。针对connect不能重启的处理方法是 , 必须调用select来等待连接完成 。
这里的“重启”怎么理解?
一些IO系统调用执行时 , 如 read 等待输入期间 , 如果收到一个信号 , 系统将中断read ,  转而执行信号处理函数. 当信号处理返回后 ,  系统遇到了一个问题: 是重新开始这个系统调用 ,  还是让系统调用失败?早期UNIX系统的做法是 ,  中断系统调用 , 并让系统调用失败 ,  比如read返回 -1 ,  同时设置 errno 为EINTR中断了的系统调用是没有完成的调用 , 它的失败是临时性的 , 如果再次调用则可能成功 , 这并不是真正的失败 , 所以要对这种情况进行处理 ,  典型的方式为:
connect处理方式 , 抄袭3原文 , 没有测试过 , 处理方法是对的 。
connect的问题 , 当connect遇到EINTR错误时 , 不能向上面那样重新进入循环处理 , 原因是 , connect的请求已经发送向对方 , 正在等待对方回应 , 这是如果重新调用connect , 而对方已经接受了上次的connect请求 , 这一次的connect就会被拒绝 , 因此 , 需要使用select或poll调用来检查socket的状态 , 如果socket的状态就绪 , 则connect已经成功 , 否则 , 视错误原因 , 做对应的处理 。


推荐阅读