c – 阻塞套接字返回EAGAIN

前端之家收集整理的这篇文章主要介绍了c – 阻塞套接字返回EAGAIN前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我在 Linux上的一个项目使用了阻塞套接字.事情发生非常连续,所以非阻塞只会让事情变得更复杂.无论如何,我发现通常recv()调用返回-1,并将errno设置为EAGAIN.

该手册页只是提到了非阻塞套接字的这种情况,这是有道理的.如果没有阻塞,则套接字可能可用,也可能不可用,因此您可能需要重试.

什么会导致阻塞套接字发生?我可以做些什么来避免它吗?

目前,我处理它的代码看起来像这样(我在错误时抛出异常,但除此之外它是一个非常简单的包装recv()):

int ret;
do {
    ret = ::recv(socket,buf,len,flags | MSG_NOSIGNAL);
} while(ret == -1 && errno == EAGAIN);


if(ret == -1) {
    throw socket_error(strerror(errno));
}
return ret;

这甚至是正确的吗? EAGAIN状况经常受到打击.

编辑:我注意到的一些可能相关的事情.

>我使用setsockopts()在套接字上设置读取超时,但设置为30秒. EAGAIN的发生方式多于每30秒一次.修正我的调试有缺陷,EAGAIN并不像我想象的那样经常发生.也许是超时触发.
>为了连接,我希望能够连接超时,所以我暂时将套接字设置为非阻塞.该代码如下所示:

int      error = 0;
fd_set   rset;
fd_set   wset;
int      n;
const SOCKET sock = m_Socket;

// set the socket as nonblocking IO
const int flags = fcntl (sock,F_GETFL,0);
fcntl(sock,F_SETFL,flags | O_NONBLOCK);

errno = 0;

// we connect,but it will return soon
n = ::connect(sock,addr,size_addr);

if(n < 0) { 
    if (errno != EINPROGRESS) {
        return -1;
    }
} else if (n == 0) {
    goto done;
}

FD_ZERO(&rset);
FD_ZERO(&wset);
FD_SET(sock,&rset);
FD_SET(sock,&wset);

struct timeval tval;
tval.tv_sec = timeout;
tval.tv_usec = 0;

// We "select()" until connect() returns its result or timeout
n = select(sock + 1,&rset,&wset,timeout ? &tval : 0);
if(n == 0) {    
    errno = ETIMEDOUT;
    return -1;
}

if (FD_ISSET(sock,&rset) || FD_ISSET(sock,&wset)) {
    socklen_t len = sizeof(error);
    if (getsockopt(SOL_SOCKET,SO_ERROR,&error,&len) < 0) {
        return -1;
    }
} else {
    return -1;
}

done:
// We change the socket options back to blocking IO
if (fcntl(sock,flags) == -1) {
    return -1;
}
return 0;

我的想法是我将其设置为非阻塞,尝试连接并在套接字上选择,以便我可以强制执行超时. set和restore fcntl()调用都成功返回,因此当此函数完成时,套接字应该再次以阻塞模式结束.

解决方法

您可能在套接字上设置了非零接收超时(通过setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,…)),因为这也会导致recv返回EAGAIN

猜你在找的C&C++相关文章