【问题标题】:Sending buffer via Boost ASIO server - sending the wrong data通过 Boost ASIO 服务器发送缓冲区 - 发送错误数据
【发布时间】:2016-02-06 22:09:55
【问题描述】:

谁能告诉我如何将存储在数组中的十六进制值原封不动地发送给客户端??

每当我通过 boost 服务器向客户端发送一个十六进制字符数组时,它会将其转换为 ASCII/JUNK(无法确定它是什么)。

例如:

我正在尝试发送

"24 bb ff 0f 02 08 01 e0 01 e0 02 08 0f 2d 0f 00 23 61"

通过 Boost asio 服务器在 char 数组中。

编辑:

客户正在接收

"32 34 62 62 66 66 30 66 30 32 30 38 30 31 65 30 30 31 65 30 30 32 30 38 30 66 32 64 30 66 30 30 32 33 36 31"

这是我正在使用的一段代码。

char Sendingdata_[512];
string finalHex = "24bbff0f020801e001e002080f2d0f002361";
strcpy(Sendingdata_, finalHex.c_str());
boost::asio::async_write(socket_, boost::asio::buffer(Sendingdata_,bytes_transferred), boost::bind(&session::handle_write, this, boost::asio::placeholders::error));

我应该使用不同的缓冲区还是任何其他方式来发送十六进制值???

【问题讨论】:

  • 请阅读stackoverflow.com/help/how-to-ask并显示发送源代码。
  • 修复字节序后,您会收到“BAADF00D BAADF00D BAADF00D ...”,因此两端都有错误,但无法猜测出在哪里。
  • 请注意,没有“十六进制值”之类的东西 - 值的十六进制表示,但是无论您是否写它,数字十都是相同的100xa,或012。不过,字符串"10" 表示数组{49, 48, 0}
  • 你应该已经包含了代码。我们不是通灵者。

标签: c++ arrays boost server boost-asio


【解决方案1】:

如果代码尝试发送超过 37 个字节,那么它将发送未初始化的内存。如果它试图发送超过 512 个字节,那么它正在读取超出缓冲区的末尾。在任何一种情况下,都可能会发送内存垃圾模式。

Sendingdata_ 缓冲区为 512 字节,但其中只有 37 个字节已初始化。

char Sendingdata_[512];                 // 512 unitialized values.
std::string finalHex = string-literal;  // 36 ASCII characters + null termination.
strcpy(Sendingdata_, finalHex.c_str()); // 37 characters copied
boost::asio::async_write(..., boost::asio::buffer(Sendingdata_, bytes_transferred), ...);

finalHex 字符串被提供了一个字符串文字。例如,将字符串字面值"2400bb" 分配给字符串,将存储'2''4''0''0''b''b' ASCII 字符。

std::string ascii = "2400bb";
assert(ascii.length() == 6);
assert('2' == ascii[0]);
assert('4' == ascii[1]);
assert('0' == ascii[2]);
assert('0' == ascii[3]);
assert('b' == ascii[4]);
assert('b' == ascii[5]);

考虑使用向量,以十六进制表示法提供数值:

std::vector<unsigned char> hex = { 0x24, 0x00, 0xbb };
assert(hex.size() == 3);
assert(0x24 == hex[0]);
assert(0x00 == hex[1]);
assert(0xbb == hex[2]);

或者,可以通过提供\x 控制字符来使用std::string 来指示后续值是十六进制。但是,在解释值时可能需要执行显式转换,并使用处理字符串中的空字符的构造函数:

std::string hex("\x24\x00\xbb", 3);
// alternatively: std::string hex{ 0x24, 0x00, static_cast<char>(0xbb) };  
assert(hex.size() == 3);
assert(0x24 == static_cast<unsigned char>(hex[0]));
assert(0x00 == static_cast<unsigned char>(hex[1]));
assert(0xbb == static_cast<unsigned char>(hex[2]));

这里是一个例子demonstrating的区别和Asio缓冲区的使用:

#include <cassert>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
#include <boost/asio.hpp>

int main()
{
  // String-literial.
  std::string ascii = "2400bb";
  assert(ascii.length() == 6);
  assert('2' == ascii[0]);
  assert('4' == ascii[1]);
  assert('0' == ascii[2]);
  assert('0' == ascii[3]);
  assert('b' == ascii[4]);
  assert('b' == ascii[5]);

  // Verify asio buffers.
  auto ascii_buffer = boost::asio::buffer(ascii);
  assert(ascii.length() == boost::asio::buffer_size(ascii_buffer));
  assert(std::equal(
    boost::asio::buffers_begin(ascii_buffer),
    boost::asio::buffers_end(ascii_buffer),
    std::begin(ascii)));

  // Hex values.
  std::vector<unsigned char> hex = { 0x24, 0x00, 0xbb };
  // alternatively: unsigned char hex[] = { 0x24, 0x00, 0xbb };
  assert(hex.size() == 3);
  assert(0x24 == hex[0]);
  assert(0x00 == hex[1]);
  assert(0xbb == hex[2]);

  // Verify asio buffers.
  auto hex_buffer = boost::asio::buffer(hex);
  assert(hex.size() == boost::asio::buffer_size(hex_buffer));
  assert(std::equal(
    boost::asio::buffers_begin(hex_buffer),
    boost::asio::buffers_end(hex_buffer),
    std::begin(hex),
    std::equal_to<unsigned char>()));

  // String with hex.  As 0x00 is in the string, the string(char*) constructor
  // cannot be used.
  std::string hex2("\x24\x00\xbb", 3);
  // alternatively: std::string hex2{ 0x24, 0x00, static_cast<char>(0xbb) };  
  assert(hex2.size() == 3);
  assert(0x24 == static_cast<unsigned char>(hex2[0]));
  assert(0x00 == static_cast<unsigned char>(hex2[1]));
  assert(0xbb == static_cast<unsigned char>(hex2[2]));
}

【讨论】:

  • 感谢@Tanner Sansbury,我发现了一些关于使用字符串的文章,正如你所解释和实现的那样,非常感谢你提供的非常有用的信息。现在我正在发送“\x24\xbb\xff\x0f\x02\x08\x01\xe0\x01\xe0\x02\x08\x0f\x2d\x0f\x00\x23\x61”,客户端只能接收“ \x24\xbb\xff\x0f\x02\x08\x01\xe0\x01\xe0\x02\x08\x0f\x2d\x0f",为什么省略最后3个十六进制值。任何想法
  • 倒数第三个值是空字符,string 使用的构造函数通过第一个空字符确定长度。使用另一个构造函数 (demo) 或其他类型,例如 vector
  • 感谢@Tanner Sansbury,感谢您的大力帮助,现在我正在通过 boost 服务器发送一个硬编码字符串,您的解决方案非常完美,但是在运行时,我找不到解决方案在每个十六进制值前插入“\x”,以便将其从“2400bb”转换为“\x24\x00\xbb”。我更喜欢字符串,因为我使用的是 VS2008。任何想法都将有助于解决这个问题。
【解决方案2】:

因为您发送的是众所周知的内存垃圾模式 (often used: 0xDEADBEEF, 0xBAADF00D, etc.),所以我假设您正在读取缓冲区末尾的内容,或者您​​正在取消引用一个过时的指针。

我看到人们使用 ASIO 时常犯的错误之一是:

void foo() {
     std::string packet = "hello world";

     boost::asio::async_write(socket_, asio::buffer(packet), my_callback);
}

问题在于将堆栈本地缓冲区与异步调用一起使用。 async_write 将立即返回,foo 将返回。 packet 可能在异步操作访问它之前就已经消失了。

如果您正在运行调试堆库,这可能是导致您读取垃圾模式而不是缓冲区内容的原因之一。

【讨论】:

  • 谢谢@sehe,是的,它发送到缓冲区的末尾,并且在客户端接收到数组中每个字符的 ASCII 之后,例如“32 34 62 62 66 66 30 66 30 32 30 38 30 31 65 30 30 31 65 30 30 32 30 38 30 66 32 64 30 66 30 30 32 33 36 31",那么我应该如何发送十六进制值而不转换为ascii,我在这里不做任何转换。我应该使用不同的缓冲区/任何数据结构吗???
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 2019-10-13
  • 2012-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多