Eva*_*ran 7 c c++ sockets linux
我在Linux上的一个项目使用了阻塞套接字.事情发生非常连续,所以非阻塞只会让事情变得更复杂.无论如何,我发现经常一个recv()调用返回-1与errno设置为EAGAIN.
该man页面只是真正提到非阻塞套接字发生这种情况,这是有道理的.如果没有阻塞,则套接字可能可用,也可能不可用,因此您可能需要重试.
什么会导致阻塞套接字发生?我可以做些什么来避免它吗?
目前,我处理它的代码看起来像这样(我在错误时抛出异常,但除此之外它是一个非常简单的包装器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;
Run Code Online (Sandbox Code Playgroud)
这甚至是正确的吗?这种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, 0, 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, F_SETFL, flags) == -1) {
return -1;
}
return 0;
Run Code Online (Sandbox Code Playgroud)我的想法是我将其设置为非阻塞,尝试连接并在套接字上选择,以便我可以强制执行超时.set和restore fcntl()调用都会成功返回,因此当此函数完成时,套接字应该再次以阻塞模式结束.
Has*_*kun 19
您可能在套接字(via setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,...))上设置了非零接收超时,因为这也会导致recv返回EAGAIN
| 归档时间: |
|
| 查看次数: |
28491 次 |
| 最近记录: |