使用luv通过管道通信时无法接收数据的问题排查与解决
使用luv库处理管道输入时无法触发回调的问题
问题描述
我正尝试使用luv库开发一款NES模拟器插件,实现不暂停游戏模拟的进程间通信。手动输入测试时运行顺畅,但通过管道与其他进程通信时,Lua脚本始终无法接收数据。
最小复现示例脚本:
local uv = require("luv") local stdin = uv.new_poll(1) stdin:start("r", function() print("uv callback") end) uv.run("once")
手动输入回车时,程序正常触发回调并退出;但通过echo | lua-5.1 min.lua管道传入空行时,无任何反应且程序不退出。已排除缓冲问题,求问问题原因及解决方法?
问题原因
核心错误是监听了错误的文件描述符:stdin对应的文件描述符是0,但你的代码中用uv.new_poll(1)监听的是stdout(文件描述符1)的可读事件。
- 终端环境下,stdout的状态变化可能意外触发回调,让你误以为是stdin输入生效;
- 管道传递输入时,数据发送到stdin(fd0),但脚本监听的是stdout(fd1),自然接收不到数据,事件循环因无待处理事件阻塞。
此外,uv.run("once")仅运行一次事件循环,无法处理管道输入结束时的stdin关闭事件,进一步导致程序无法退出。
解决方案
修改脚本,正确监听stdin的文件描述符,并完善事件循环和关闭逻辑:
local uv = require("luv") local stdin = uv.new_poll(0) -- 改为stdin对应的文件描述符0 stdin:start("r", function(err, events) if err then print("Error:", err) stdin:stop() uv.stop() return end if events then print("uv callback") -- 读取数据,避免可读事件重复触发 local data = uv.read(0, 4096) -- 数据为空表示stdin已关闭(管道输入结束) if not data or #data == 0 then stdin:stop() uv.stop() end end end) uv.run() -- 运行事件循环直到所有handle停止
关键修改说明
- 修正文件描述符:将
1改为0,确保监听stdin的可读事件; - 处理关闭事件:当stdin被关闭(管道输入完成)时,主动停止poll handle并终止事件循环;
- 调整事件循环模式:使用
uv.run()替代uv.run("once"),保证所有相关事件(包括关闭通知)都能被处理; - 读取数据避免重复触发:调用
uv.read()读取输入数据,防止未读取的数据持续触发可读事件。
测试验证:运行echo | lua-5.1 min.lua,脚本会正确触发回调并退出;手动输入回车时也能正常工作。
内容的提问来源于stack exchange,提问作者Daniel Wagner
相关产品推荐
相关产品推荐

