2011-11-12 94 views
4

我正在尝试制作一个简单的客户端 - 服务器聊天程序。在客户端,我分离出另一个线程来读取来自服务器的任何传入数据。问题是,当一个人从主线程注销时,我想优雅地终止第二个线程。我试图使用共享变量'running'来终止,问题是,socket read()命令是一个阻塞命令,所以如果我这样做(运行== 1),服务器必须在读取返回之前发送一些内容并且可以再次检查时间条件。我正在寻找一种方法(只有常见的unix套接字)来执行非阻塞式读取,基本上某种形式的peek()可以工作,因为我可以不断检查循环以查看是否完成。C- Unix套接字 - 无阻塞读取

阅读线程循环如下,现在它没有共享变量的任何互斥量,但我打算补充,以后不用担心! ;)

void *serverlisten(void *vargp) 
{ 
    while(running == 1) 
    { 
     read(socket, readbuffer, sizeof(readbuffer)); 
     printf("CLIENT RECIEVED: %s\n", readbuffer); 
    } 
    pthread_exit(NULL); 
} 

回答

8

可以使插座无法阻断的,在另一篇文章中建议加用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 
+0

sd + 1在这种情况下意味着什么?我像这样运行它,并且它能够工作,但它会像循环20次那样循环,然后停止,直到创建新输入,但它像我想要的那样优雅地终止,唯一的问题是20次。它几乎就像它在超时或运行期间运行的那样 – will

+0

您可以在终端中输入“man select”以获取选择功能的详细说明。因为在这里我们只有一个描述符,所以我只写(sd + 1)。 – fghj

+0

大约20次不了解说明。我的代码在你的第一个问题的上下文应该是这样的:1)检查标志(退出的时间?)2)睡眠直到输入或超时3)读取一些东西4)goto(1)。所以它会延迟退出。但是你应该处理另一方关闭连接时的情况,然后选择返回控制给你,但是“读取”将读取0字节,并且你得到了繁忙循环。所以你应该检查“read”的结果,如果它为零,则退出循环。 – fghj

6
fcntl(socket, F_SETFL, O_NONBLOCK); 

,或者如果你有其他的标志:

int x; 
x=fcntl(socket ,F_GETFL, 0); 
fcntl(socket, F_SETFL, x | O_NONBLOCK); 

然后检查的读取返回值,看看是否有可用的数据。

注意:一点谷歌搜索会产生很多完整的例子。

您也可以使用阻塞套接字,并在select超时时使用“peek”。在这里似乎更合适,所以你不必忙于等待。

1

查找功能setsockopt与选项SO_RCVTIMEO

2

最好的事情是可能摆脱多余的线程,并使用select()poll()来处理一个线程中的所有内容。

如果你想保持线程,你可以做的一件事情是调用shutdown()套接字SHUT_RDWR,这将关闭连接,唤醒所有阻塞的线程,但保持文件描述符有效。加入阅读器线程后,可以关闭套接字。请注意,这只适用于套接字,而不适用于其他类型的文件描述符。

0

这可能不是您正在寻找的具体答案,但它可能是您可以找到它的地方。我目前正在读:

Unix Network Programming, Volume 1: The Sockets Networking API, 3rd Edition

而且有很多的多线程,非阻塞的服务器和客户端的例子。此外,他们解释了很多不同方法之间的推理和权衡。

希望可以帮到...

+0

通过广告的链接。伟大的举动! ;) –

+0

@YagamyLight欢迎您添加您想要的任何非广告链接。我与亚马逊或Addison-Wesley没有任何关系。然而,连接到亚马逊使其可以购买,预览和评论,并且通常是一个稳定的URL,不会在不久的将来过期。 – Homer6

+0

我并不是指亚马逊,我的意思是说,链接本身通过一个神秘的[rads.stackoverflow.com](http://rads.stackoverflow.com/amzn/click/0131411551)。但是,那就是说,我已经发现你的帖子中没有这个链接,所以这似乎是StackOverflow本身的恶作剧。顺便说一句,只是好奇 - 你在帖子中看到这样一个链接(我只是认为链接可以从作者隐藏)? –