【问题标题】:C- Unix Sockets - Non-blocking readC- Unix 套接字 - 非阻塞读取
【发布时间】:2011-12-27 18:44:50
【问题描述】:

我正在尝试制作一个简单的客户端-服务器聊天程序。在客户端,我分拆另一个线程来读取来自服务器的任何传入数据。问题是,当有人从主线程注销时,我想优雅地终止第二个线程。我试图使用共享变量 'running' 来终止,问题是,套接字 read() 命令是一个阻塞命令,所以如果我这样做 while(running == 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);
}

【问题讨论】:

    标签: c multithreading sockets unix


    【解决方案1】:
    fcntl(socket, F_SETFL, O_NONBLOCK);
    

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

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

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

    注意:稍微用谷歌搜索一下就会得到很多完整的示例。

    您还可以使用阻塞套接字,并使用select“窥视”并设置超时。这里似乎更合适,所以你不要忙着等待。

    【讨论】:

      【解决方案2】:

      您可以使套接字不可阻塞,如另一篇文章中所建议的那样,加上使用 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
      

      【讨论】:

      • sd+1 在这种情况下是什么意思?我像这样运行它,它工作,但它会像循环一样循环 20 次,然后停止,直到创建新的输入,但是它确实像我想要的那样优雅地终止,唯一关心的是 20 次。它几乎就像它在超时期间运行一样
      • 您可以在终端输入“man select”来获取选择功能的详细说明。由于第一个参数 selct 取最大的值描述符加 1。因为这里我们只有一个描述符,所以我只写 (sd + 1)。
      • 听不懂注20次左右。我的代码在你的第一个问题的上下文中应该是这样的:1)检查标志(退出时间?) 2)睡眠直到输入或超时 3)读一些东西 4)转到(1)。所以它会延迟退出。但是你应该处理对方关闭连接的情况,然后选择返回控制给你,但是“读取”会读取 0 个字节,你会得到繁忙的循环。所以你应该检查“读取”的结果,如果它为零则退出循环。
      • 我想通了,谢谢,是我在没有输入的情况下在循环内打印,这是一个冲洗问题已经解决,谢谢你的帮助:)
      【解决方案3】:

      查找带有选项SO_RCVTIMEO 的函数setsockopt

      【讨论】:

        【解决方案4】:

        最好的办法可能是去掉多余的线程,使用select()poll()在一个线程中处理所有事情。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-01-16
          • 1970-01-01
          • 2012-06-13
          • 2012-07-24
          • 2016-04-11
          • 1970-01-01
          • 1970-01-01
          • 2010-10-31
          相关资源
          最近更新 更多