我想创建一个字符缓冲区,使用sprintf写入它,然后将它传递给async_write()的多个调用(即将它分发给一组客户端)。我的问题是用于此的最佳数据结构是什么?如果存在妥协,那么我认为定义“最佳”的优先级将是:
以下是我目前的工作原理:
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);
}
然后:
void client_session::write(boost::shared_ptr<std::string> msg){
if(!socket->is_open())return;
boost::asio::async_write(*socket,
boost::asio::buffer(*msg),
boost::bind(&client_session::handle_write, shared_from_this(),_1,_2,msg)
);
}
注意:
msg
必须超出我的第一个代码段(asio要求),因此使用共享指针。我认为我可以在所有标准上做得更好。我想知道使用boost :: shared_array?或者直接从我的char buf [512]创建一个asio :: buffer(用智能指针包装)?但阅读关于这些和其他选择的文档让我对所有可能性感到不知所措。
另外,在我当前的代码中,我将msg作为参数传递给handle_write(),以确保在达到handle_write()之前不释放智能指针。那是必需的不是吗?
更新:如果您认为整体情况更好,我愿意用sprintf
或类似内容替换std::stringstream
。问题的关键是我需要撰写一条消息然后广播它,我想有效地做到这一点。
UPDATE#2(2012年2月26日):我很欣赏人们发布答案的麻烦,但我觉得他们都没有真正回答过这个问题。没有人发布代码显示更好的方法,也没有任何数字来支持它们。事实上,我的印象是人们认为当前的方法和它一样好。
答案 0 :(得分:3)
首先,请注意您将原始缓冲区而不是消息传递给write函数,我认为您不打算这样做吗?
如果您打算发送纯文本邮件,则可以先使用std::string
和std::stringstream
开头,无需传递固定大小的数组。
如果你需要做更多的二进制/字节格式化,我肯定会开始用字符向量替换固定大小的数组。在这种情况下,我也不会先进行将其转换为字符串的往返,而是直接从字节向量构造asio缓冲区。如果您不必使用预定义协议,则更好的解决方案是使用Protocol Buffers或Thrift或任何可行的替代方案。这样您就不必担心字节序,重复,可变长度项,向后兼容性......等。
shared_ptr
技巧确实是必要的,你需要存储缓冲区引用的数据,直到消耗缓冲区为止。不要忘记有些替代方案可以更清晰,比如将它存储在client_session
对象本身中。但是,如果这是可行的,则取决于如何构造消息传递对象;)。
答案 1 :(得分:1)
您可以在client_session对象中存储std::list<boost::shared_ptr<std::string> >
,并让client_session::write()
对其进行push_back()
。我认为这巧妙地避免了boost.asio
的功能。
答案 2 :(得分:1)
因为我需要向许多客户发送相同的消息。实施会有点复杂。
我建议将消息准备为boost::shared_ptr<std::string>
(建议使用@KillianDS)以避免额外的内存使用和从char buf[512];
进行复制(在任何情况下都不安全,您无法确定你的程序将来会发展,如果这种能力在所有情况下都足够了)。
然后将此消息推送到内部std::queue
内部的每个客户端。如果队列为空并且没有待处理的文档(对于此特定客户端,请使用布尔标志来检查) - 从队列中弹出消息并将async_write
弹出到套接字,将shared_ptr
作为参数传递给完成handler(传递给async_write
的仿函数)。调用完成处理程序后,您可以从队列中获取下一条消息。 shared_ptr
引用计数器将使消息保持活动状态,直到最后一个客户端将其足够地发送到套接字。
此外,我建议限制最大队列大小,以便在网络速度不足时减慢消息创建速度。
修改强>
通常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
。