c-如何在recv调用上干净地中断线程阻塞



我有一个用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 datan");
// Clean-up code.

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

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

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

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

(1) pthread_kill会用errno==EINTR将线程从recv中吹出,您可以自己清理并退出线程。有些人认为这很恶心。真的要看情况。

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

(3) 在与(2)的组合中,使每个线程与主线程共享一个管道。将其添加到select中。如果它变得可读并且包含一个shutdonw请求,线程就会关闭自己。

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

关闭套接字以从另一个线程进行输入。这将导致读取线程接收EOS,这将导致它关闭套接字并在正确写入的情况下终止。

要中断线程,请使套接字不阻塞(使用fcntl设置O_NONBLOCK),然后用pthread_kill向线程发出信号。这样,如果recv正在休眠,则它将与EINTREAGAINEWOULDBLOCK一起失败(也可能是如果SA_RESTART有效,则未检查)。请注意,在此之前,套接字不需要也不应该是非阻塞的。(当然,信号需要处理;空的处理程序就足够了)。

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

该做什么:

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

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

最新更新