将uin32_t写入 asio::streambuf

Writing uin32_t to asio::streambuf

提问人:Braaedy 提问时间:8/13/2017 更新时间:8/13/2017 访问量:528

问:

我正在尝试将写入将要通过网络发送的缓冲区中,但我不确定如何正确操作。最初,我假设这将正确处理它并将 4 个字节写入缓冲区(假设我以前使用过)。相反,我开始得到没有任何意义的值。我注意到,有时将单个 int 写入流有时会将缓冲区的大小增加多达 10 个字节,而不是预期的 4 个字节。我写了一个简短的测试,并意识到它实际上是将 ascii 中的整数转储到缓冲区。我想我已经找到了解决它的方法,但它感觉很笨拙,所以我正在寻找一种更好的方法,或者解释为什么我正在做的事情实际上是正确的。uint32_toperator<<htonl

下面是一些示例代码:

  boost::asio::streambuf buffer;
  std::ostream os(&buffer);

  uint32_t value = 0x12345678;
  os << value; // Gives ascii 305419896

  os.write((const char *) &value, sizeof(value)); // fives 0x12345678

有没有比我的最后一行代码更好的方法?

C++ C++11 加速 boost-ASIO IOstream

评论

1赞 Geoffrey 8/13/2017
还要记住,int 将使用本地机器的原生字节序(小/大)打包......最好确保网络端序使用和/或类似,以确保将来的兼容性。此外,该方法是AFAIK无论如何执行此操作的最佳方法。如果您有更多字段,最好制作一个打包的结构,然后一次性将整个结构写入流。htonlntohlwrite
0赞 Braaedy 8/13/2017
我确实说过我正在使用 htonl。特别是对于这一点,我不能使用打包结构,但这是一个好主意,我知道我将来很快就会使用。
0赞 Geoffrey 8/13/2017
对不起,我错过了那部分。您可能要考虑的另一件事是运行长度编码以节省带宽,具体取决于您的要求。
0赞 Braaedy 8/13/2017
感谢您的建议,如有必要,我会考虑使用它。

答:

1赞 yuri kilochek 8/13/2017 #1

你正在做的事情很好,但可以直接写入 streambuf:

buffer.commit(boost::asio::buffer_copy(
    buffer.prepare(sizeof(value)),
    boost::asio::buffer(&value, sizeof(value))));
0赞 Blacktempel 8/13/2017 #2

这是通常的做法。如果在两者之间添加一些代码,则可以节省一些时间和代码。

template<class T> void append(T value)
{
    static_assert(std::is_fundamental<T>::value, __FUNCTION__);
    //Convert here to correct endian
    append(reinterpret_cast<const char*>(&value), sizeof(value));
}

template<class T> void append(const T *app, std::size_t size)
{
    return append(reinterpret_cast<const char*>(app), size);
}

void append(const char *s, std::size_t length)
{
    //append to buffer
}

请记住在收到数据时转换为正确的字节序。或者,如果您知道远程计算机的期望,则直接以正确的格式发送它。

您也可以像这样检查字节序:

static bool IsBigEndian(void)
{
    union
    {
        uint32_t i;
        char c[4];
    } endi = { 0x01020304 };
    return endi.c[0] == 1;
}

评论

0赞 Paul R 8/13/2017
在运行时检查字节序是多余的,因为您在编译时就已经知道了。
0赞 Blacktempel 8/13/2017
我知道这一点。这是一个建议,你可以从答案中读到。