Chrome原生消息主机消息长度为256倍数时无法读取问题求助
Chrome原生消息(Native Messaging)特定长度消息解析失败问题解决
问题现象
开发Chrome扩展通过Native Messaging Host传输DOM信息时,发现当纯消息长度为256的倍数加10/20/30(比如266=256+10,对应含头总长度270)时,Chrome停止解析原生主机的stdout,触发异常:The sender sent an invalid JSON message; message ignored.,随后关闭连接。原生主机持续发送数据但无响应。
核心原因
Windows平台下,C++的std::cout默认使用文本模式,而非Native Messaging要求的二进制模式。文本模式会自动转换换行符(如\n转\r\n),或把特定字节(如0x1A)视为EOF截断输出,导致实际发送的字节数与头部声明的长度不匹配,Chrome解析JSON时因数据损坏报错。
你的代码仅设置了stdin的二进制模式,但遗漏了stdout的二进制模式配置,这是问题的根本所在。
解决方案
在原生主机的main函数中,同时将stdout设置为二进制模式:
修改后的C++代码片段
int main(int argc, char *argv[]) { // 设置stdin为二进制模式 if (_setmode(_fileno(stdin), _O_BINARY) == -1) { Log("[Error]. Could not set input mode to binary"); return 1; } // 设置stdout为二进制模式(关键修复) if (_setmode(_fileno(stdout), _O_BINARY) == -1) { Log("[Error]. Could not set output mode to binary"); return 1; } // 后续逻辑保持不变 std::this_thread::sleep_for(std::chrono::seconds(5)); for (int i = 1; i < 100000; i++) { nlohmann::json jj = {{"msg", ""}}; for (int j = 0; j < i; j++) { jj["msg"] += "a"; } std::string s = jj.dump(); SendExtMessage(s); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } return 0; }
额外优化建议
- 移除临时添加的虚拟字节逻辑,因为根本问题解决后无需再规避长度:
// 恢复原始的SendExtMessage函数,去掉长度判断和虚拟字段 void SendExtMessage(std::string msg) { uint32_t responseLen = msg.length(); char *bt_len = reinterpret_cast<char *>(&responseLen); std::cout.write(bt_len, 4); std::cout.write(msg.c_str(), responseLen); std::cout.flush(); Log("[Log] Writing " + std::to_string(responseLen) + " bytes to stdout"); }
- 确保JSON序列化无异常:使用
nlohmann::json的dump时,默认会处理特殊字符,无需额外转义,但可以添加错误检查确保JSON有效:
try { std::string s = jj.dump(); SendExtMessage(s); } catch (const nlohmann::json::exception& e) { Log("[Error] JSON serialization failed: " + std::string(e.what())); }
验证步骤
- 重新编译原生主机,确保stdout二进制模式已设置;
- 运行扩展,测试原问题中的敏感长度(如2560+10=2570字节的纯消息);
- 查看Chrome后台日志,确认所有长度的消息都能正常接收,无连接断开或JSON错误。
内容的提问来源于stack exchange,提问作者Nikos Papachatzakis
相关产品推荐
相关产品推荐

