C- Unix套接字 - 非阻塞读取

时间:2011-11-12 20:18:30

标签: c multithreading sockets unix

我正在尝试制作一个简单的客户端 - 服务器聊天程序。在客户端,我分拆另一个线程来读取服务器上的任何输入数据。问题是,当一个人从主线程注销时,我想优雅地终止第二个线程。我试图使用共享变量'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);
}

5 个答案:

答案 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

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

希望有帮助...