使用boost::asio时与std::string替代方案是什么?

19

boost::asio 的各种 readwrite 函数和方法接受 boost::asio::buffer。根据buffer文档,不可变的 std::string 无法包装在 boost::asio::buffer 中,因此不能用于 asio 的 read 函数。这可能是因为 std::string 不允许可变访问其内部缓冲区(曾在此处讨论here)。

这真是太遗憾了,因为 std::string 是表示 C++ 中可变数据缓冲区的方便方式。没有它,我们只能使用 POD 数组、boost::arraystd::vector<char>。前两者对于可变长度的消息很不方便。std::vector<char> 可以工作,但它是一种不自然的携带数据缓冲区的方式 (*)。

问题:

  1. 除了 std::string 之外,在使用 boost::asio 读取缓冲区时还有其他选择吗?我是否遗漏了些什么?
  2. 我想知道为什么可变缓冲区支持 std::vector<char>。这是因为它保证其内部缓冲区在内存中是连续的,并允许使用 &vec [0] 进行可变访问吗?

提前感谢。


(*) 在我看来。例如,看看 protobuf 序列化 - 它提供了对 std::string 的序列化,但至少没有明确提供对 std::vector<char> 的序列化。

编辑:最终我还是使用了vector<char>。通过SerializeToArray调用,protobuf可以将序列化后的内容转换为vector<char>,并且可以传递一个指针(即&vec[0])。


3
通常我使用 vector<char> - 因为在对接收到的数据进行处理的所有情况下,我发现这种方法更快。但是我也看到了 asio::streambuf 的使用: http://www.boost.org/doc/libs/1_40_0/doc/html/boost_asio/reference/streambuf.html。 - Nim
@Nim: 我考虑过 asio::streambuf,但它在固定大小的读取上似乎有问题,更适合像HTTP中的read_until。但我可能漏掉了什么... - Eli Bendersky
@Mattieu M.:我认为protobuf并不提议将序列化输出为纯文本,它的序列化输出明显看起来像二进制数据(而不是ASCII码)。 - Eli Bendersky
1
@Eli,我不确定你所说的asio::streambuf在固定大小读取方面存在什么问题。我已经在几个项目中成功使用它,并且它与Boost.Serialization很好地集成在一起。你能否编辑你的问题以澄清你的疑虑? - Sam Miller
@Sam:我最初在问题中没有提到asio::streambuf,确实是因为我不完全清楚如何将其与固定大小的读取和asio一起使用。你能否指出一个示例(或在答案中添加一个)来展示如何将固定长度的块读入std::stringstream - Eli Bendersky
显示剩余3条评论
3个回答

8

在所有已知的实现中,使用&str[0]可以对字符串缓冲区进行可变访问,并且即将到来的C++0x标准化措辞也正式允许此操作。

尽管如此,我认为认为std::vector是一个不自然的变长缓冲区表示方式是疯狂的想法。


Ben,这听起来不错,但是asio :: buffer没有采用非const std :: string的构造函数,那么你如何将其传递到asio中呢?可能是因为asio目前不希望依赖于严格标准之外的行为吗? - Eli Bendersky
1
std::stringasio::buffer 的转换: asio::buffer(&str[0], str.size()) - Ben Voigt
@Ben:你有这项调查的参考资料吗?我想多了解一些。 - murrekatt
1
@Alan:不能保证对 c_str() 缓冲区所做的更改会被合并到字符串中,也不能保证缓冲区本身是可写的。 - Ben Voigt
@murrekatt: 在这里阅读评论:http://herbsutter.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/ Herb Sutter是C++标准委员会的成员之一,曾担任委员会主席。 - Ben Voigt
显示剩余3条评论

5

这是回答Eli评论的内容

我最初在问题中没有提到asio::streambuf,确实是因为我不确定如何在固定大小读取和asio中使用它。您能否指出一个示例(或将其作为答案添加),以显示如何将固定长度块读入std :: sstream?

这里有先前的答案关于使用asio :: streambuf和Boost.Serialization。 asio 文档还有一个同步读取的示例:

boost::asio::streambuf b;

// reserve 512 bytes in output sequence
boost::asio::streambuf::mutable_buffers_type bufs = b.prepare(512);

size_t n = sock.receive(bufs);

// received data is "committed" from output sequence to input sequence
b.commit(n);

std::istream is(&b);
std::string s;
is >> s;

2

1) 通过检查返回mutable_buffers_1的重载函数,可以找到 asio::buffer() 函数的替代方案。更灵活(但可能不是最优)的选择是 asio::streambuf,对于 (async_)read_until 很有用。

如果您有固定大小的字段协议,可以使用 asio::mutable_buffer 数组。例如:

using boost::asio;
int i;
short s;
char data[data_size]; // data_size is defined elsewhere
boost::array<asio::mutable_buffer, 3> bufs = {
    asio::buffer(&i, 4), 
    asio::buffer(&s, 2),
    asio::buffer(data, data_size)
};
asio::read(socket, buffer(bufs)); // socket defined elsewhere

2) 您已经参考了这个问题的很好答案:"如何使用Boost::asio异步读取到std::string?"


是的,确实你在这里列出的所有内容都已经在我的问题中提到了(包括固定数组方法)。不管怎样,感谢你的确认 :-) - Eli Bendersky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接