如何有效地使用boost asio套接字进行全双工流式传输?

时间:2011-07-19 21:31:40

标签: c++ boost streaming boost-asio duplex

我正在使用boost.asio编写性能关键的双向流服务器 服务器以这种方式工作:

  • 线程A处理并推送要在OUTPUT队列中发送的对象
  • 线程B等待INPUT队列中的对象来处理它们
  • 线程C是一个接受器线程,它接受传入的客户端并为每个客户端创建一个CLIENT类

多个客户端同时运行,每个客户端都有自己的连接套接字,每个客户端必须同时执行两项操作:

  • 等待(条件变量)至少一个对象出现在OUTPUT队列中(这可能需要很长时间)并尽可能快地发送
  • 从套接字获取任何传入对象,并将其放入INPUT队列

此外,性能和多核可扩展性在此应用程序中至关重要。

标准异步方法在这里失败(发送回调可能在等待新对象发送时阻止其他回调)和阻塞方法(每个方向使用1个线程)很复杂,我无法弄清楚该做什么如果其中一个线程发生错误。

我应该为每个客户端使用2个套接字(一个用于输出,一个用于输入)?或者可能以某种方式在每个套接字上使用两个io_services,在两个不同的线程上进行并发回调支持?

请解释我如何处理这种情况。 谢谢。

1 个答案:

答案 0 :(得分:5)

  

此处标准异步方法失败(发送回调可能会阻止   等待新对象发送时的其他回调)

异步模型应该可以正常工作,如果正确使用肯定会更好地扩展 - 它只会在你引入阻塞时崩溃。而不是抛弃异步,这是我的建议:

删除条件变量。您需要两个队列:OUTPUT和WAITING。

然后在处理客户时:

  1. 如果OUTPUT队列中有数据,请发送它。
  2. 如果没有,请将其推送到WAITING队列。
  3. 不需要在前一个I / O的处理程序中执行下一个I / O.这里不是阻塞条件变量,而是将其移到WAITING队列上以便以后处理。

    在OUTPUT推送代码中:

    1. 如果WAITING队列中有客户端,则直接发送数据。
    2. 如果没有,请按下OUTPUT队列。
    3. 这是一些伪代码:

      queue<packet> output;
      queue<client> waiting;
      
      void try_send(client c)
      {
          if(!output.empty())
          {
              // there is output waiting to be sent, send it.
              packet p = output.pop();
              c.async_send(p, on_send_finished);
          }
          else
          {
              // nothing available, go back to waiting.
              waiting.push(c);
          }
      }
      
      void on_send_finished(client c)
      {
          // send finished, try again if any more output has accumulated:
          try_send(c);
      }
      
      void push_output(packet p)
      {
          output.push(p);
      
          if(!waiting.empty())
          {
              // there is a client waiting to send, give it a try.
              client c = waiting.pop();
              try_send(c);
          }
      }
      

      这可以使用单个线程以可扩展的方式完成,但使用asio可以轻松实现多个线程。如果您要使用多个线程,则需要在检查队列的逻辑中引入锁定。