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

C-Unix套接字-非阻塞读取,c,multithreading,sockets,unix,C,Multithreading,Sockets,Unix,我正在尝试制作一个简单的客户端-服务器聊天程序。在客户端,我剥离另一个线程,从服务器读取任何输入数据。问题是,当一个人从主线程注销时,我想优雅地终止第二个线程。我试图使用一个共享变量“running”来终止,问题是,socket read()命令是一个阻塞命令,所以如果我在while(running==1)执行此操作,服务器必须在读取返回之前发送一些内容,并且可以再次检查while条件。我正在寻找一种方法(只使用普通的unix套接字)来进行非阻塞读取,基本上某种形式的peek()可以工作,因为我

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

下面是读取线程循环,现在它没有任何用于共享变量的互斥锁,但我计划稍后添加它(不要担心!)

或者,如果您有其他标志:

int x;
x=fcntl(socket ,F_GETFL, 0);
fcntl(socket, F_SETFL, x | O_NONBLOCK);
然后检查read的返回值,查看是否有可用数据

注意:一点谷歌搜索会给你提供很多完整的例子


您还可以使用阻塞套接字,并使用带超时的
select
进行“窥视”。这里似乎更合适,这样您就不用忙着等待了。

您可以使套接字不可阻止,正如另一篇文章中所建议的那样,使用select to wait input with timeout,如下所示:

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

使用选项
查找函数
setsockopt
,因此最好的办法是去掉多余的线程,使用
select()
poll()
在一个线程中处理所有事情


如果要保留线程,可以使用
shutdown\u RDWR
在套接字上调用
shutdown()
,这将关闭连接,唤醒所有阻塞的线程,但保持文件描述符有效。加入读卡器线程后,可以关闭套接字。请注意,这只适用于套接字,而不适用于其他类型的文件描述符。

sd+1在本文中是什么意思?我这样运行它,它工作了,但它会在循环中循环20次,然后停止,直到创建了新的输入,但是它确实像我所希望的那样优雅地终止,唯一关心的是20次。它几乎像是在超时或其他什么时候运行的。您可以在终端中键入“man select”以获得选择功能的详细说明。作为第一个参数,selct采用最大的值描述符加1。因为在这里我们只有一个描述符,我只写了(sd+1),大概20次都不懂。在第一个问题的上下文中,我的代码应该是这样工作的:1)检查标志(退出时间?)2)睡眠直到输入或超时3)读取内容4)转到(1)。所以它会延迟退出。但你们应该处理另一方关闭连接时的情况,然后选择ReturnControl给你们,但“read”将读取0字节,你们将得到繁忙的循环。所以你应该检查“读取”的结果,如果结果为零,则退出循环。我算出了,谢谢,这是因为我在循环内打印时没有输入,这是一个刷新问题,所有问题都解决了,谢谢你的帮助:)
int x;
x=fcntl(socket ,F_GETFL, 0);
fcntl(socket, F_SETFL, x | O_NONBLOCK);
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