我正在尝试制作一个简单的客户端 - 服务器聊天程序。在客户端,我分拆另一个线程来读取服务器上的任何输入数据。问题是,当一个人从主线程注销时,我想优雅地终止第二个线程。我试图使用共享变量'running'来终止,问题是,socket read()命令是一个阻塞命令,所以如果我这样做(运行== 1),服务器必须在读取之前发送一些东西并且可以再次检查while条件。我正在寻找一种方法(仅使用常见的unix套接字)来执行非阻塞读取,基本上某种形式的peek()可以工作,因为我可以不断检查循环以查看是否已完成。
读取线程循环在下面,现在它没有任何共享变量的互斥锁,但我打算稍后添加,不要担心! ;)
void *serverlisten(void *vargp)
{
while(running == 1)
{
read(socket, readbuffer, sizeof(readbuffer));
printf("CLIENT RECIEVED: %s\n", readbuffer);
}
pthread_exit(NULL);
}
答案 0 :(得分:8)
你可以使socket无法阻塞,正如另一篇文章所建议的那样,使用select来等待输入超时,如下所示:
fd_set input;
FD_ZERO(&input);
FD_SET(sd, &input);
struct timeval timeout;
timeout.tv_sec = sec;
timeout.tv_usec = msec * 1000;
int n = select(sd + 1, &input, NULL, NULL, &timeout);
if (n == -1) {
//something wrong
} else if (n == 0)
continue;//timeout
if (!FD_ISSET(sd, &input))
;//again something wrong
//here we can call not blockable read
答案 1 :(得分:7)
fcntl(socket, F_SETFL, O_NONBLOCK);
或者,如果你有其他标志:
int x;
x=fcntl(socket ,F_GETFL, 0);
fcntl(socket, F_SETFL, x | O_NONBLOCK);
然后检查read的返回值以查看是否有可用的数据。
注意:一些谷歌搜索会产生很多完整的示例。
你也可以使用阻塞套接字,并使用select
“偷看”超时。这似乎更合适,所以你不要忙着等。
答案 2 :(得分:2)
最好的办法是摆脱额外的线程并使用select()
或poll()
来处理一个线程中的所有内容。
如果你想保留线程,你可以做的一件事是用shutdown()
在套接字上调用SHUT_RDWR
,这将关闭连接,唤醒阻塞它的所有线程,但保留文件描述符有效。加入阅读器线程后,您可以关闭套接字。请注意,这仅适用于套接字,而不适用于其他类型的文件描述符。
答案 3 :(得分:1)
使用选项setsockopt
查找功能SO_RCVTIMEO
。
答案 4 :(得分:0)
这可能不是您正在寻找的具体答案,但它可能是您可以找到它的地方。我正在读:
Unix Network Programming, Volume 1: The Sockets Networking API, 3rd Edition
还有很多多线程,非阻塞服务器和客户端的例子。此外,他们解释了不同方法之间的许多推理和权衡。
希望有帮助...