Chrome扩展仅在端口断开时发送NativeMessage问题求助
问题描述
我按照Chrome Native Messaging文档实现了一个简单扩展,核心代码如下:
const port = chrome.runtime.connectNative('com.the.app'); port.postMessage('FIRST MESSAGE'); port.postMessage('Second Message');
同时开发了一个二进制程序,接收标准输入并写入logs.txt,通过以下测试确认程序正常工作:
./the_binary <<< 'test' # logs.txt now includes 'test'
但启用Chrome扩展时,logs.txt无内容;禁用扩展或点击扩展刷新按钮(断开端口并重新运行扩展代码)时,消息才会发送至logs.txt。
注:二进制程序完全不输出stdout,仅向stderr输出内容,清楚stdout输出会干扰进程。
原因分析
问题出在二进制程序的输入读取逻辑:
- 测试命令
./the_binary <<< 'test'会将输入一次性发送并关闭stdin,程序能读取到完整输入; - 但Chrome Native Messaging是持续字节流通信,不会主动关闭stdin(除非端口断开)。如果程序是等待**EOF(输入结束)**才开始读取处理,就会一直阻塞,直到扩展端口断开(禁用/刷新)时才触发EOF,读取到缓冲中的所有数据;
- 另外,系统默认的stdin缓冲(行缓冲/块缓冲)也会导致数据暂存,无法实时传递给程序。
解决方法
1. 修改二进制程序的读取逻辑,适配Native Messaging协议
Chrome Native Messaging的消息格式要求:每个消息前加4字节小端序的长度前缀,后跟JSON格式的消息内容。程序需要循环执行以下步骤:
- 读取4字节数据,解析为小端序整数(即消息内容的字节长度);
- 根据解析出的长度,读取对应字节数的消息内容;
- 处理消息(写入logs.txt);
- 回到第一步,等待下一个消息。
示例(C语言伪代码):
#include <stdio.h> #include <stdint.h> int main() { // 禁用stdin缓冲,确保数据实时读取 setvbuf(stdin, NULL, _IONBF, 0); while (1) { uint32_t len; // 读取4字节长度前缀(小端序) if (fread(&len, sizeof(len), 1, stdin) != 1) { break; // 连接断开,退出循环 } // 转换为小端序(大端系统需要,小端系统可省略) len = __builtin_bswap32(len); // 读取对应长度的消息内容 char buf[len + 1]; if (fread(buf, len, 1, stdin) != 1) { break; } buf[len] = '\0'; // 添加字符串结束符 // 写入日志文件 FILE* fp = fopen("logs.txt", "a"); fprintf(fp, "%s\n", buf); fclose(fp); } return 0; }
2. 确保stdin无缓冲
在程序初始化时禁用stdin的缓冲机制,避免系统暂存数据,确保能实时读取Chrome发送的字节流。不同语言的实现方式:
- Python:使用
sys.stdin.buffer.read()直接操作字节流,默认无缓冲; - Go:使用
os.Stdin.Read()直接读取,无缓冲。
扩展代码验证
你的扩展代码本身是正确的:chrome.runtime.connectNative的postMessage会自动将消息序列化为JSON,并添加Native Messaging要求的长度前缀,无需手动处理。
内容的提问来源于stack exchange,提问作者Mehdi Hoseini
相关产品推荐
相关产品推荐

