C++ 将超时设置为 recv 函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30395258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:46:12  来源:igfitidea点击:

Setting timeout to recv function

c++socketsvisual-c++recv

提问by vico

I read from socket using recvfunction. I have problem when no data available for reading. My programm just stops. I found that I can set timeout using selectfunction. But looks that timeout affects select function itself and recvthat goes after select still waits uncontinuously.

我使用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)
      {
      ...
      }

How to ask recvfunction return after some timout?

recv超时后如何要求函数返回?

采纳答案by Nemanja Boric

You should check return value of select. selectwill return 0in case timeout expired, so you should check for error and call recvonly if selectreturned positive value:

您应该检查 的返回值selectselect0在超时到期时返回,因此您应该检查错误并recv仅在select返回正值时调用:

On success, select() and pselect() return the number of file descriptors contained in the three returned descriptor sets (that is, the total number of bits that are set in readfds, writefds, exceptfds) which may be zero if the timeout expires before anything interesting happens.

成功时,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...
    }
}

回答by Remy Lebeau

Another way to set a timeout on recv()itself without using select()is to use setsockopt()to set the socket's SO_RCVTIMEOoption (on platforms that support it).

另一种在recv()不使用的情况下设置超时的方法select()是使用setsockopt()设置套接字的SO_RCVTIMEO选项(在支持它的平台上)。

On Windows, the code would look like this:

在 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)
        //...
}

On other platforms, the code would look like this instead:

在其他平台上,代码看起来像这样:

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))
        //...
}

回答by Richard Hodges

use the FD_ISSET() macro to test whether there is data to read. If it returns false, don't do the read.

使用 FD_ISSET() 宏来测试是否有数据要读取。如果返回 false,则不进行读取。

http://linux.die.net/man/3/fd_set

http://linux.die.net/man/3/fd_set