【问题标题】:Server with multiple clients - writing with select()具有多个客户端的服务器 - 使用 select() 编写
【发布时间】:2012-01-30 06:18:32
【问题描述】:

我正在尝试编写一个同时处理多个客户端的服务器。显然我应该使用select。我找到了很多教程,但没有一个能处理写作。

我知道我应该如何读取数据,但是在我的“循环”中处理写回客户端的正确方法是什么?

提前致谢。

【问题讨论】:

    标签: c++ sockets asynchronous


    【解决方案1】:

    实际上,我认为您想使用 poll() 而不是 select() 但这不是重点。要写入多个客户端,您需要确保不使用阻塞写入。您可能不会检测特定对象是否可以消化更多数据而侥幸,因此您可能不需要在编写时使用 poll()(或 select())。但是,如果您想为客户端以不同的速度消费数据做好准备,您可能希望在客户端可以消化更多数据时收到通知。

    除此之外,poll() 或 select() 可以通知读取缓冲区中可用的数据或写入缓冲区中可用的空间。除了需要设置不同的标志外,用法几乎相同。

    【讨论】:

      【解决方案2】:

      如果您有想要发送到特定套接字的数据,那么当该套接字的输出缓冲区中有可用空间时,您需要 select() 返回。告诉 select() 这样做的方法类似于使用 select() 仅用于读取 - 除了您也在第二个 fd_set 对象上执行 FD_SET。

      int socks[10] = {... some client sockets...}
      
      while(1)
      {
         fd_set readSet, writeSet;
      
         FD_ZERO(&readSet);
         FD_ZERO(&writeSet);
      
         int maxSock = -1;
         for (int i=0; i<10; i++)
         {
            FD_SET(socks[i], &readSet);
            if (socks[i] > maxSock) maxSock = socks[i];
      
            if (IHaveDataToSendToThisSocket(i))  // implement this function as appropriate to your program
            {
               FD_SET(socks[i], &writeSet);
               if (socks[i] > maxSock) maxSock = socks[i];
            }
         }
      
         int ret = select(maxSock+1, &readSet, &writeSet, NULL, NULL);
         if (ret < 0)
         {
            perror("select() failed");
            break;
         }
      
         // Do I/O for sockets that are ready
         for (int i=0; i<10; i++)
         {
            if (FD_ISSET(socks[i], &readSet))
            {
               // there is data to read on this socket, so call recv() on it
            }
      
            if (FD_ISSET(socks[i], &writeSet))
            {
               // this socket has space available to write data to, so call send() on it
            }
         }
      }
      

      【讨论】:

      • 非常感谢。我感到困惑的部分是,对于阅读,我所要做的就是(a)等待数据并(b)将其读入。对于写作,我如何判断我是否有要写入的数据?我应该将它存储在像全局向量之类的东西中吗?
      • 我需要根据发送给我的内容回信给客户。当我收到信号告诉我可以再次写入时,我将如何访问读取的数据?
      • 您是否有要写入套接字的数据取决于您的应用程序执行的操作。对于您的情况:如果您想让服务器通过在同一个套接字上发送回一些其他数据来响应接收到的数据,那么对于每个套接字,您应该有一些数据结构来表示该套接字的“对话状态”。
      • 例如,如果你知道你的服务器的响应总是小于 100 字节,你可以(对于每个套接字)有一个 100 个字符的数组,一个表示这个数组的偏移量的整数(设置为零)和一个表示数组中有效字节数的整数(也设置为零)。然后,当您从套接字获取一些数据时,您会将响应字节放入套接字的数组中,并将该套接字的有效字节数整数设置为您放置的字节数。如果偏移整数小于有效字节数,则实现 IHaveDataToSendToThisSocket() 以返回 true。
      • ... 最后,当 FD_ISSET(socks[i], &writeSet) 返回 true 时,您将从缓冲区中发送()尽可能多的剩余有效字节,并将偏移量增加您发送的字节数。当偏移值等于 number-of-valid-bytes 值时,您就知道您已经发送了整个响应。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-02
      相关资源
      最近更新 更多