二进制包中的转义字符 (0x1b/27) 不会通过 Wi-Fi 发送,并且在传输过程中会损坏消息
Escape characters (0x1b/27) in binary packages don't get sent through Wi-Fi and corrupt message during transmission
我在嵌入式系统(STM32F4)上开发,我试图将一些数据发送到PC端的一个简单的Windows Forms客户端程序。当我使用基于字符的字符串格式时,一切正常,但是当我更改为二进制包以提高性能时,我 运行 遇到转义字符问题。
我正在使用 nanopb 来实现用于传输的 Google 协议缓冲区,我观察到在 5% 的包中我在客户端程序中收到异常,告诉我我的包已损坏。
我在 WireShark 中调试,发现在这个损坏的包中,大小比原始包小 2-4 个字节。进一步检查后,我发现损坏的包始终包含二进制值 27,而其他包从未包含此值。我搜索了一下,发现这个值代表一个转义字符,这可能会导致问题。
我使用的 Wi-Fi 模块 (Gainspan GSM2100) 的技术文档提到命令前面有一个转义字符,所以我想我需要在我的包中去掉这个值。
我找不到解决我的问题的方法,所以如果有更有经验的人能引导我找到解决这个问题的正确方法,我将不胜感激。
你是如何发送数据的?您是在使用库还是发送原始字节?根据 the manual,您的数据命令应以转义序列开头,但还指定了 数据长度:
// Each escape sequence starts with the ASCII character 27 (0x1B),
// the equivalent to the ESC key. The contents of < > are a byte or byte stream.
// - Cid is connection id (udp, tcp, etc)
// - Data Length is 4 ASCII char represents decimal value
// i.e. 1400 bytes would be '1' '4' '0' '0' (0x31 0x34 0x30 0x30).
// - Data size must match with specified length.
// Ignore all command or esc sequence in between data pay load.
<Esc>Z<Cid><Data Length xxxx 4 ascii char><data>
注意关于数据大小的备注:"Ignore all command or esc sequence in between data pay load".
例如,GSCore::writeData function in GSCore.cpp 是这样的:
// Including a trailing 0 that snprintf insists to write
uint8_t header[8];
// Prepare header: <esc> Z <cid> <ascii length>
snprintf((char*)header, sizeof(header), "\x1bZ%x%04d", cid, len);
// First, write the escape sequence up to the cid. After this, the
// module responds with <ESC>O or <ESC>F.
writeRaw(header, 3);
if (!readDataResponse()) {
if (GS_LOG_ERRORS && this->error)
this->error->println("Sending bulk data frame failed");
return false;
}
// Then, write the rest of the escape sequence (-1 to not write the
// trailing 0)
writeRaw(header + 3, sizeof(header) - 1 - 3);+
// And write the actual data
writeRaw(buf, len);
这很可能会奏效。或者,一个肮脏的 hack 可能 在发送之前到 "escape the escape character",即在发送之前用两个字符 (0x27 0x27) 替换每个 0x27 - 但这只是一个疯狂的猜测,我是假设你应该检查一下手册。
我在嵌入式系统(STM32F4)上开发,我试图将一些数据发送到PC端的一个简单的Windows Forms客户端程序。当我使用基于字符的字符串格式时,一切正常,但是当我更改为二进制包以提高性能时,我 运行 遇到转义字符问题。
我正在使用 nanopb 来实现用于传输的 Google 协议缓冲区,我观察到在 5% 的包中我在客户端程序中收到异常,告诉我我的包已损坏。
我在 WireShark 中调试,发现在这个损坏的包中,大小比原始包小 2-4 个字节。进一步检查后,我发现损坏的包始终包含二进制值 27,而其他包从未包含此值。我搜索了一下,发现这个值代表一个转义字符,这可能会导致问题。
我使用的 Wi-Fi 模块 (Gainspan GSM2100) 的技术文档提到命令前面有一个转义字符,所以我想我需要在我的包中去掉这个值。
我找不到解决我的问题的方法,所以如果有更有经验的人能引导我找到解决这个问题的正确方法,我将不胜感激。
你是如何发送数据的?您是在使用库还是发送原始字节?根据 the manual,您的数据命令应以转义序列开头,但还指定了 数据长度:
// Each escape sequence starts with the ASCII character 27 (0x1B),
// the equivalent to the ESC key. The contents of < > are a byte or byte stream.
// - Cid is connection id (udp, tcp, etc)
// - Data Length is 4 ASCII char represents decimal value
// i.e. 1400 bytes would be '1' '4' '0' '0' (0x31 0x34 0x30 0x30).
// - Data size must match with specified length.
// Ignore all command or esc sequence in between data pay load.
<Esc>Z<Cid><Data Length xxxx 4 ascii char><data>
注意关于数据大小的备注:"Ignore all command or esc sequence in between data pay load".
例如,GSCore::writeData function in GSCore.cpp 是这样的:
// Including a trailing 0 that snprintf insists to write
uint8_t header[8];
// Prepare header: <esc> Z <cid> <ascii length>
snprintf((char*)header, sizeof(header), "\x1bZ%x%04d", cid, len);
// First, write the escape sequence up to the cid. After this, the
// module responds with <ESC>O or <ESC>F.
writeRaw(header, 3);
if (!readDataResponse()) {
if (GS_LOG_ERRORS && this->error)
this->error->println("Sending bulk data frame failed");
return false;
}
// Then, write the rest of the escape sequence (-1 to not write the
// trailing 0)
writeRaw(header + 3, sizeof(header) - 1 - 3);+
// And write the actual data
writeRaw(buf, len);
这很可能会奏效。或者,一个肮脏的 hack 可能 在发送之前到 "escape the escape character",即在发送之前用两个字符 (0x27 0x27) 替换每个 0x27 - 但这只是一个疯狂的猜测,我是假设你应该检查一下手册。