我有一个用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
发生,这实际上并不准确。
或者,我有更好的方法来处理错误吗?
答案 0 :(得分:9)
所以你至少有这些可能性:
(1)pthread_kill
将使用errno == EINTR将线程从recv
中删除,您可以自行清理并退出该线程。有些人认为这很讨厌。真的,取决于。
(2)使您的客户端套接字无阻塞并使用select
等待输入一段特定的时间,然后检查线程之间使用的交换机是否已设置为表明它们应该关闭下来。
(3)在(2)的组合中,每个线程与主线程共享一个管道。将其添加到select
。如果它变得可读并包含一个shutdonw请求,则线程会自行关闭。
(4)如果上述(或其变体)都不符合您的需求,请查看pthread_cancel
机制。
答案 1 :(得分:3)
关闭套接字以从另一个线程输入。这将导致读取线程接收到EOS,这应该导致它关闭套接字并在正确写入时终止。
答案 2 :(得分:0)
要中断线程,请使套接字成为非阻塞状态(使用O_NONBLOCK
设置fcntl
),然后用pthread_kill
发出信号。这样,recv
将在EINTR
处于休眠状态时失败,或者EAGAIN
或EWOULDBLOCK
不在休眠状态(也可能是SA_RESTART
在效果,没有检查)。请注意,在此之前,套接字不需要而且实际上应该是非阻塞的。 (当然也需要处理信号;空的处理程序就足够了。)
为确保捕获停止信号但别无其他,请使用标志;有些事情可能出问题了。例如,在某些虚假信号上,recv
可能因EINTR
而失败。否则,如果有可用数据有效地忽略了停止请求,它可能会成功。
以及不要做的事情:
请勿单独使用pthread_kill
或进行任何简单的检查。它可能在发出recv
syscall之前就到达了,太早了,无法中断,但要经过所有检查。
不要close
插入套接字。这可能甚至行不通,而且@R ..指针向外输出很危险,因为套接字文件描述符可能在close
和recv
之间重用(除非您确定没有打开文件描述符)。 / p>