L011Linux和androidNDK之socket出错情况的处理:Interrupted system call,Try again

L011Linux和androidNDK之socket出错情况的处理:Interrupted system call,Try again

socket一些出错的情况,并不需要直接结束本次交互,还可以重新启动交互,比如Interrupted system call,Try again。

Timer expired

超时,对于非阻塞的调用,超时系统有一个默认值,不同的系统有不同的设置。(可参看L009Linux和androidNDK之linux网络通讯超时时间设置)
如果有设置的话,则使用设置的值。

Interrupted system call

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

适用于慢系统调用的基本规则是:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应处理函数返回时,该系统调用可能返回一个EINTR错误。所以,我们必须对慢系统调用返回的EINTR有所准备。

为了处理被中断的accept,可以改成如下形式:

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

这段代码所做的事情就是自己重启被中断的系统调用。对于accept,以及诸如read、write、select和open之类的函数,这是适合的。不过有一个函数我们不能重启:connect。如果该函数返回EINTR,我们就不能再次调用它,否则将立即返回一个错误。当connect被一个捕获信号中断而且不自动重启时,我们必须调用select来等待连接完成。
(出自unix网络编程(第三版)第五章 P115页)

Try again

socket设置SO_RCVTIMEO和SO_SNDTIMEO对read/write的影响?看man怎么说

SO_RCVTIMEO and SO_SNDTIMEO

Specify the receiving or sending timeouts until reporting an error. The argument is a struct timeval. If an input or output function blocks for this period of time, and data has been sent or received, the return value of that function will be the amount of data transferred; if no data has been transferred and the timeout has been reached then -1 is returned witherrno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just as if the socket was specified to be nonblocking. If the timeout is set to zero (the default) then the operation will never timeout. Timeouts only have effect for system calls that perform socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect for select(2), poll(2), epoll_wait(2), and so on.

即SO_RCVTIMEO和SO_SNDTIMEO会导致read/write函数返回EAGAIN

另外,在确定错误过程中,同事提到O_NODELAY会导致write接口返回EAGAIN,的确,如果设置了O_NODELAY而当前不可写,那么write接口会设置errno为EAGAIN,但是write接口会返回0而不是-1.在本案中,hiredis接口中并没有设置O_NODELAY

参考链接

  1. 阻塞socket上read/write出现errno为EAGAIN的原因解密
  2. Socket编程中Interrupted system call 解释及解决办法
  3. L009Linux和androidNDK之linux网络通讯超时时间设置

你可能感兴趣的:(L011Linux和androidNDK之socket出错情况的处理:Interrupted system call,Try again)