我使用recv
函数从套接字读取。没有可供阅读的数据时,我遇到了问题。我的程序停止了。我发现我可以使用select
函数设置超时。但看起来超时会影响select函数本身,而recv
会在select之后仍然等待不连续。
fd_set set;
struct timeval timeout;
FD_ZERO(&set); /* clear the set */
FD_SET(s, &set); /* add our file descriptor to the set */
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC;
timeout.tv_usec = 0;
int rv = select(s, &set, NULL, NULL, &timeout);
if((recv_size = recv(s , rx_tmp , bufSize ,0)) == SOCKET_ERROR)
{
...
}
如何在一些时间后问recv
函数返回?
答案 0 :(得分:23)
在不使用recv()
的情况下在select()
上设置超时的另一种方法是使用setsockopt()
设置套接字的SO_RCVTIMEO
选项(在支持它的平台上)。 / p>
在Windows上,代码如下所示:
DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
//...
recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAETIMEDOUT)
//...
}
在其他平台上,代码看起来像这样:
struct timeval timeout;
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC;
timeout.tv_usec = 0;
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
//...
recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == -1)
{
if ((errno != EAGAIN) && (errno != EWOULDBLOCK))
//...
}
答案 1 :(得分:8)
您应该检查select
的返回值。如果超时超时,select
将返回0
,因此您应检查错误,并仅在recv
返回正值时致电select
:
成功时,select()和pselect()返回三个返回的描述符集中包含的文件描述符的数量(即readfds,writefds,exceptfds中设置的总位数),如果超时在任何有趣的事情发生之前到期。
int rv = select(s + 1, &set, NULL, NULL, &timeout);
if (rv == SOCKET_ERROR)
{
// select error...
}
else if (rv == 0)
{
// timeout, socket does not have anything to read
}
else
{
// socket has something to read
recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == SOCKET_ERROR)
{
// read failed...
}
else if (recv_size == 0)
{
// peer disconnected...
}
else
{
// read successful...
}
}
答案 2 :(得分:1)
使用FD_ISSET()宏来测试是否有要读取的数据。如果它返回false,则不进行读取。