我找到了一些关于如何执行此操作的提示,但我不明白如何使用setsockopt。我有一个无限的 while 循环调用 recv,我想超时并且close(cli_socket)如果客户端在 5 秒内没有发送任何内容。
如果客户端仅发送整个预期消息的一部分,我想重置计时器并再给他 5 秒钟。
目前我有这个:
while((cut = buffer.find("\r\n")) == -1)
{
struct timeval tv;
tv.tv_sec = 5;
setsockopt(cli_socket, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));
recv(cli_socket, tmpBuffer, 100, 0);
buffer += tmpBuffer;
memset(tmpBuffer, 0, 100);
}
Run Code Online (Sandbox Code Playgroud)
recv您应该测试和break循环的返回是否为EAGAINor EWOULDBLOCK:
EAGAIN 或 EWOULDBLOCK
套接字被标记为非阻塞并且接收操作将阻塞,或者已设置接收超时并且在接收数据之前超时已过期
struct timeval tv = {5, 0};
setsockopt(cli_socket, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
while((cut = buffer.find("\r\n")) == -1)
{
int numBytes = recv(cli_socket, tmpBuffer, 100, 0));
/// Edit: recv does not return EAGAIN else, it return -1 on error.
/// and in case of timeout, errno is set to EAGAIN or EWOULDBLOCK
if (numBytes <= 0)
{
// nothing received from client in last 5 seconds
break;
}
buffer.append(tmpBuffer, numBytes);
}
Run Code Online (Sandbox Code Playgroud)
您还可以使用select使用起来并不复杂的函数:
while((cut = buffer.find("\r\n")) == -1)
{
timeval timeout = { 5, 0 };
fd_set in_set;
FD_ZERO(&in_set);
FD_SET(cli_socket, &in_set);
// select the set
int cnt = select(cli_socket + 1, &in_set, NULL, NULL, &timeout);
if (FD_ISSET(cli_socket, &in_set))
{
int numBytes = recv(cli_socket, tmpBuffer, 100, 0));
if (numBytes <= 0)
{
// nothing received from client
break;
}
buffer.append(tmpBuffer, numBytes);
}
else
{
// nothing received from client in last 5 seconds
break;
}
}
Run Code Online (Sandbox Code Playgroud)