【发布时间】:2021-02-18 12:01:27
【问题描述】:
我正在尝试使用setsockopt 与SO_SNDTIMEO 和SO_RCVTIMEO 在Linux 上设置阻塞TCP 套接字的超时。但由于某种原因,我在等待recv 呼叫时得到了锁。
考虑最小的例子。为了便于阅读,我将其缩短了一点,完整的代码可在此gist 中找到。我创建了一个服务器套接字并使用setsockopt 设置超时。接下来,服务器与客户端交换消息。一段时间后,客户端中断数据交换并关闭套接字。但是服务器仍在等待阻塞recv。但是,我希望它在超时到期时中止recv。
客户端和服务器使用的网络功能:
int set_timeout(int fd, int sec) {
struct timeval timeout;
timeout.tv_sec = sec;
timeout.tv_usec = 0;
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout)) < 0) {
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
sizeof(timeout)) < 0) {
return -1;
}
return 0;
}
int blocking_recv(int sock, char *data, size_t size) {
size_t remain_data = size;
ssize_t recv_nb;
int offset = 0;
while ((remain_data > 0) &&
((recv_nb = recv(sock, data + offset, remain_data, 0)) >= 0)) {
remain_data -= recv_nb;
offset += recv_nb;
}
if (recv_nb == -1 || remain_data > 0) {
return -1;
}
return 0;
}
int blocking_send(int sock, char *buf, size_t size) {
size_t total = 0;
int remain = size;
int n;
while (total < size) {
n = send(sock, buf + total, remain, 0);
if (n == -1) {
break;
}
total += n;
remain -= n;
}
return (total == size) ? 0 : -1;
}
服务器:
while (1) {
struct sockaddr_in caddr;
size_t len = sizeof(caddr);
if ((client_fd = accept(server_fd, (struct sockaddr *)&caddr, (socklen_t *)&len)) < 0) {
continue;
}
// Set 3 seconds timeout using SO_{SND,RCV}TIMEO
if (set_timeout(client_fd, 3) != 0) {
continue;
}
// Send and receive data in the loop. We assume that the client is stuck,
// we'll break the connection using a timeout.
while (1) {
char in_data[data_size];
char *out_data = "test\0";
if (blocking_recv(client_fd, in_data, data_size) != 0)
break;
if (blocking_send(client_fd, out_data, data_size) != 0)
break;
}
}
客户:
int attempts_left = 5;
while (--attempts_left > 0) {
char in_data[6];
char *out_data = "test\0";
if (blocking_send(fd, out_data, 6) != 0)
break;
if (blocking_recv(fd, in_data, 6) != 0)
break;
sleep(1);
}
close(fd);
可能出了什么问题?
不使用select、poll和信号,是否可以通过这种方式实现recv的超时?
谢谢!
【问题讨论】:
-
((recv_nb = recv(sock, data + offset, remain_data, 0)) >= 0)好吧,你永远不会退出,所以......你只是循环。 -
@KamilCuk 啊,你是对的,这很愚蠢。对不起这个噪音。如果您发布它,我可以接受您的回答。
-
FWIW,超时在这里不会起作用...当客户端关闭套接字时,服务器会收到通知(它基本上会创建一个 EOF 条件),而无需任何等待。