10

我有一个用 C 编写的多线程服务器,每个客户端线程看起来像这样:

ssize_t n;
struct request request;

// Main loop: receive requests from the client and send responses.
while(running && (n = recv(sockfd, &request, sizeof(request), 0)) == sizeof(request)) {
    // Process request and send response.
}
if(n == -1)
    perror("Error receiving request from client");
else if(n != sizeof(act))
    fprintf(stderr, "Error receiving request from client: Incomplete data\n");

// Clean-up code.

在某些时候,客户端满足必须断开连接的特定标准。如果客户端定期发送请求,这很好,因为它可以在响应中被告知断开连接;然而,有时客户端需要很长时间才能发送请求,因此客户端线程最终会在recv调用中阻塞,并且客户端直到下一个请求/响应才会断开连接。

当客户端线程在调用中阻塞时,是否有一种干净的方法可以将客户端与另一个线程断开连接recv?我试过close(sockfd)了,但这会导致错误Error receiving request from client: Bad file descriptor发生,这确实不准确。

或者,有没有更好的方法让我在这里处理错误?

4

3 回答 3

10

所以你至少有这些可能性:

(1)pthread_kill将使用 errno == EINTR 将线程吹出recv,您可以自行清理并退出线程。有些人认为这很恶心。取决于,真的。

(2) 使您的客户端套接字非阻塞,并select在检查线程之间使用的开关是否已设置为指示它们应该关闭之前等待输入特定时间段。

(3) 结合 (2) 让每个线程与主线程共享一个管道。将其添加到select. 如果它变得可读并包含关闭请求,则线程将自行关闭。

(4)pthread_cancel如果以上(或其变体)都不能满足您的需求,请查看机制。

于 2013-07-23T22:43:13.457 回答
4

关闭套接字以获取来自另一个线程的输入。这将导致读取线程接收到一个 EOS,这将导致它关闭套接字并在正确写入时终止。

于 2013-07-24T00:34:47.620 回答
0

要中断线程,请使套接字非阻塞(O_NONBLOCK使用设置fcntl),然后使用 向线程发出信号pthread_kill。这样,如果它正在睡觉,或者它不是(也可能是如果有效,没有检查) ,recv它将失败。请注意,在此之前,套接字不需要,实际上也不应该是非阻塞的。(当然需要处理信号;空处理程序就足够了)。EINTREAGAINEWOULDBLOCKSA_RESTART

为了确保捕捉到停止信号而不是其他任何东西,请使用标志;有些事情可能会出错。例如,recv可能会EINTR因某些虚假信号而失败。或者如果有一些可用的数据,它可能会成功,有效地忽略停止请求。

什么不该做:

  1. 不要pthread_kill单独使用或与任何普通支票一起使用。它可能会在发出recv系统调用之前到达,但在所有检查之后中断它还为时过早。

  2. 不要close插座。这甚至可能不起作用,并且作为@R.. 指针,是危险的,因为套接字文件描述符可能会在close和之间重用recv(除非您确定没有打开文件描述符)。

于 2019-01-30T22:40:49.133 回答