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

dmp*_*p32 3 c++ streaming boost duplex boost-asio

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

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

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

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

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

标准的异步方法在这里失败(发送回调可能会在等待新对象发送时阻止其他回调)和阻塞方法(每个方向使用1个线程)很复杂,我无法弄清楚如何处理其中一个线程出错.

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

请解释一下你将如何应对这种情况.谢谢.

Cor*_*son 5

标准异步方法在这里失败(发送回调可能在等待新对象发送时阻止其他回调)

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

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

然后在处理客户端时:

  1. 如果OUTPUT队列中有数据,则发送它.
  2. 如果没有,请将其推送到WAITING队列.

不需要在前一个I/O的处理程序中执行下一个I/O. 这里不是阻塞条件变量,而是将其移到WAITING队列上以便以后处理.

在OUTPUT推送代码中:

  1. 如果WAITING队列中有客户端,则直接发送数据.
  2. 如果没有,请按下OUTPUT队列.

这是一些伪代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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