我正在设计一个带线程池的多线程服务器。该系统旨在使用持久性TCP连接,因为客户端将保持接近24/7的连接。我遇到的问题是如何管理关机。目前,通过“accept(listen_fd ....)”进入连接,并将其分配给工作订单结构。此结构被转储到工作队列中,并由线程拾取。从这一点开始,这个线程专门用于当前连接。我在线程中的代码是:
/* Function which runs in a thread to handle a request */
void *
handle_req( void *in)
{
ssize_t n;
char read;
/* Convert the input to a workorder_ptr */
workorder_t *workorder_ptr = (workorder_t *)in;
while( !serv_shutdown
&& (n=recv(workorder_ptr->sock_fd,&read,1,0) != 0))
{
printf("Read a character: %c\n",read);
}
printf("Peer has shutdown.\n");
/* Free the workorder memory */
close(workorder_ptr->sock_fd);
free(workorder_ptr);
return NULL;
}
它只是简单地监听套接字并无限期地回显字符,并在客户端终止连接时正确运行。你在while循环中看到“!serv_shutdown”部分 - 这是我尝试让线程在关闭信号上突破其循环。捕获SIGINT时,全局变量设置为1.不幸的是,程序当前在recv语句上阻塞,并且在读取另一个字符之前不会检查此标志。我想避免这种情况,因为在此连接上发送另一个字符之前可能是一段任意时间。
另外,我在另一篇文章中读到,最好使用“select”而不是“accept”等待套接字连接,但我不太明白。你会选择等待,然后在那之后做一个接受吗?我不确定select如何创建套接字连接。我问这个,因为如果我对选择的理解被澄清了,那么它可能适用于我要问的问题吗?
另外,我如何检测连接只是超时的情况?
谢谢!
修改 我想在进一步挖掘后我可能终于找到了解决方案:
Wake up thread blocked on accept() call
基本上,我可以创建一个全局管道,让每个线程在自己的socket_fd以及这个全局管道上进行选择。然后,当一个信号被捕获时,我只会写一些东西给管道。所有线程都应该被唤醒,不是吗?
答案 0 :(得分:1)
好吧,在FreeBSD,MacOSX和其他地方都有kevent()调用,它允许监听广泛的系统事件,包括连接请求和数据到达套接字时的信令。 它将以一种简洁的方式解决您的所有问题,但它不可移植。有一些libs,例如libevent和libev,它们包含特定于操作系统的功能,如BSD上的kevent(),Linux上的epoll()等等。可能会帮助你。
答案 1 :(得分:1)
您可以使用recv()
原语。如果它返回0,则表示套接字已关闭。
更多信息:http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#recvman