C++ asio:存储要广播的消息的最佳方式

C++ asio:存储要广播的消息的最佳方式,c++,containers,boost-asio,C++,Containers,Boost Asio,我想创建一个字符缓冲区,使用sprintf写入,然后将其传递给多个async_write()调用(即,将其分发给一组客户端)。我的问题是,用于此目的的最佳数据结构是什么?如果存在妥协,那么我想定义“最佳”的优先事项是: 更少的CPU周期 代码清晰度 更少的内存使用 以下是我目前拥有的,似乎有效的: function broadcast(){ char buf[512]; sprintf(buf,"Hello %s","World!"); boost::shared_ptr<st

我想创建一个字符缓冲区,使用sprintf写入,然后将其传递给多个async_write()调用(即,将其分发给一组客户端)。我的问题是,用于此目的的最佳数据结构是什么?如果存在妥协,那么我想定义“最佳”的优先事项是:

  • 更少的CPU周期
  • 代码清晰度
  • 更少的内存使用
  • 以下是我目前拥有的,似乎有效的:

    function broadcast(){
      char buf[512];
      sprintf(buf,"Hello %s","World!");
      boost::shared_ptr<std::string> msg(new std::string(buf));
      msg->append(1,0);   //NUL byte at the end
    
      for(std::vector< boost::shared_ptr<client_session> >::iterator i=clients.begin();
        i!=clients.end();++i) i->write(buf);
    }
    
    函数广播(){
    char-buf[512];
    sprintf(buf,“你好%s”,“世界!”);
    boost::shared_ptr msg(新std::string(buf));
    msg->append(1,0);//末尾有NUL字节
    对于(std::vector::迭代器i=clients.begin();
    i!=clients.end();++i)i->write(buf);
    }
    
    然后:

    void client_session::write(boost::shared_ptr msg){
    如果(!socket->is_open())返回;
    boost::asio::异步写入(*socket,
    boost::asio::buffer(*msg),
    boost::bind(&client_session::handle_write,shared_from_this(),_1,_2,msg)
    );
    }
    
    注:

    • 典型的消息大小将小于64字节;512缓冲区大小简直是妄想症
    • 我传递一个NUL字节来标记每条消息的结尾;这是协议的一部分
    • msg
      必须在我的第一个代码段(asio要求)之外运行,因此使用了共享指针
    我认为我可以在所有标准上做得更好。我想知道如何使用boost::shared_阵列?或者直接从我的char buf[512]创建asio::buffer(包装在智能指针中)?但是阅读这些和其他选择的文档让我被所有的可能性所淹没

    另外,在我当前的代码中,我将msg作为参数传递给handle_write(),以确保在到达handle_write()之前不会释放智能指针。这是必须的,不是吗

    更新:如果你认为它总体上更好,我愿意用一个
    std::stringstream
    或类似的东西来代替
    sprintf
    。问题的关键是,我需要撰写一条消息,然后进行广播,我想有效地做到这一点


    更新#2(2012年2月26日):我很感激人们在发布答案时遇到的麻烦,但我觉得没有人真正回答了这个问题。没有人发布代码来显示更好的方法,也没有人给出任何数字来支持它们。事实上,我得到的印象是,人们认为当前的方法和它得到的一样好。

    首先,请注意,您正在将原始缓冲区而不是消息传递给write函数,我认为您不是有意这样做的

    如果您计划发送纯文本消息,您可以简单地使用
    std::string
    std::stringstream
    开始,而无需传递固定大小的数组

    如果您需要进行更多的二进制/字节格式化,我肯定会首先用字符向量替换固定大小的数组。在本例中,我也不会首先将其转换为字符串,而是直接从字节向量构造asio缓冲区。如果您不必使用预定义的协议,更好的解决方案是使用类似或任何可行的替代方案。这样,您就不必担心诸如结尾、重复、可变长度项、向后兼容性等问题


    shared\u ptr
    技巧确实是必要的,您确实需要将缓冲区引用的数据存储在某个地方,直到缓冲区被使用为止。别忘了还有一些更清晰的替代方案,比如只将其存储在
    client\u会话
    对象本身中。但是,这是否可行取决于消息传递对象的构造方式;)

    您可以在客户端会话对象中存储
    std::list
    ,并让
    client\u会话::write()
    在其上执行
    push\u-back()
    。我认为这是巧妙地避免了boost.asio的功能。

    正如我所了解的,您需要向许多客户端发送相同的消息。实现过程会稍微复杂一些

    我建议您准备一条消息作为
    boost::shared_ptr
    (建议使用@KillianDS),以避免额外的内存使用和从
    char buf[512]复制(在任何情况下都不安全,您无法确定您的程序在未来将如何发展,以及在所有情况下该容量是否足够)

    然后将此消息推送到每个客户端内部
    std::queue
    。如果队列为空且没有挂起的写入(对于此特定客户端,请使用布尔标志检查此情况)-将消息从队列中弹出并
    async\u write
    将其作为完成处理程序的参数传递到套接字
    shared\u ptr
    (传递到
    async\u write
    )中。调用完成处理程序后,您可以从队列中获取下一条消息
    shared_ptr
    reference计数器将使消息保持活动状态,直到最后一个客户端将其成功发送到套接字

    此外,我建议限制最大队列大小,以在网络速度不足时减慢消息创建速度

    编辑

    通常,
    sprintf
    在安全成本方面更有效。如果性能是关键的并且
    std::stringstream
    是一个瓶颈
    ,您仍然可以将
    sprintf
    std::string
    一起使用:

    std::string buf(512, '\0');
    sprintf(&buf[0],"Hello %s","World!");
    

    请注意,
    std::string
    不保证将数据存储在连续内存块中,这与
    std::vector
    相反(如果C++11的情况发生了更改,请纠正我)。实际上,
    std::string
    的所有流行实现都使用连续内存。或者,您可以在上面的示例中使用
    std::vector

    谢谢@KillianDS。关于你的第一点,我展示的代码是有效的,也是他们在教程中如何做到的:(关于你的最后一点,他们将std::string存储在类对象中;bu
    std::string buf(512, '\0');
    sprintf(&buf[0],"Hello %s","World!");