我正在尝试从Linux上的/ dev / input / by-id /读取输入设备事件。我尝试在项目中使用input-event npm程序包,但是当我尝试使用CTRL + C停止它并需要kill -9时,它挂了我的整个终端。我以为是程序包故障,但事实证明,让我监听SIG信号实际上是一个问题:
process.on('SIGINT', function() { exitHandler('SIGINT'); });
process.on('SIGUSR1', function() { exitHandler('SIGUSR1'); });
process.on('SIGUSR2', function() { exitHandler('SIGUSR2'); });
process.on('SIGTERM', function() { exitHandler('SIGTERM'); });
当我删除侦听器时,它开始正常工作(可以CTRL + C移出节点)。如果我保留侦听器,但删除readStreams,它也可以工作。我尝试在process.exit()之前关闭流和文件描述符,但是它不起作用。 这是我的代码:
const fs = require('fs');
let monitoredDevices = {
devices: [],
addDevice: function(path) {
fs.open(path, 'r', (e, fd) => {
if(e)
return;
let dev = { path: path, fd: null, stream: null};
dev.fd = fd;
// comment out the stream and it process can exit normally
dev.stream = fs.createReadStream(null, { fd: dev.fd, mode: 'r'});
let ix = this.devices.push(dev);
if(dev.stream) {
dev.stream.on('data', (data) => {
console.log('DATA('+dev.path+'):', data);
});
dev.stream.on('error', (e) => {
if(e.code == 'ENODEV') {
// disconnected
this.devices.splice(ix, 1);
fs.closeSync(dev.fd);
dev.stream.close();
delete dev;
}
});
}
});
},
hasDevice: function(path) {
return this.devices.find(x => x.path == path) ? true : false;
}
};
setInterval(function() {
// Query /dev/input/by-id/ for new connected devices and open readstream on new ones
fs.readdir('/dev/input/by-id', (err, files) => {
if(err)
return;
files.forEach(file => {
if(fs.lstatSync('/dev/input/by-id/'+file).isDirectory())
return;
if(monitoredDevices.hasDevice('/dev/input/by-id/'+file))
return;
monitoredDevices.addDevice('/dev/input/by-id/'+file);
console.log('EVENT:', file);
});
});
}, 500);
let _shutdownInProcess = false;
function exitHandler(signal='') {
if(!_shutdownInProcess) {
_shutdownInProcess = true;
for(let i = 0; i < monitoredDevices.devices.length; i++) {
console.log('Closing ' + monitoredDevices.devices[i].path + ' (' + monitoredDevices.devices[i].fd +')', fs.closeSync(monitoredDevices.devices[i].fd));
monitoredDevices.devices[i].stream.close();
}
console.log('\033[31m Caught exit signal ' + signal + ', closing... \x1b[0m');
process.exit();
}
}
// Comment out the events and the process exist properly
process.on('SIGINT', function() { exitHandler('SIGINT'); });
process.on('SIGUSR1', function() { exitHandler('SIGUSR1'); });
process.on('SIGUSR2', function() { exitHandler('SIGUSR2'); });
process.on('SIGTERM', function() { exitHandler('SIGTERM'); });
这显然需要root特权才能读取输入事件。
当我CTRL + C(或执行killall node
)时,会退出exitHandler,但它会在红色控制台日志后立即停止,并且我无法在该终端上执行任何操作。只有killall -9 node
有效。
我在这里发现了类似的问题:Node.js process.exit() will not exit with a createReadStream open
但这并不能真正解决问题,只能强制终止该过程。有什么方法可以迫使流在退出之前关闭?不幸的是,在退出之前,我需要使用这些信号侦听器,因为我正在使用它们来做其他事情。
答案 0 :(得分:0)
这似乎是node.js内核内部的错误,该错误从开始就存在,并且没有计划予以修复(Readline文档中对此有警告)。因此,我使用了一个简单的cat
子进程,并使用了它的stdout而不是创建自己的流,就像一个符咒一样,但是除了检查流本身是否存在ENODEV错误外,您还需要检查进程退出,因为cat已经存在当设备停止存在时。
dev.proc = require('child_process').spawn('cat', [path]);
dev.stream = dev.proc.stdout;