简体   繁体   English

如何使 node.js 中的 fs.read 超时?

[英]How to timeout an fs.read in node.js?

I try to read from a filedescriptor with fs.read.我尝试使用 fs.read 从文件描述符中读取。 The callback-function is called after it got the data.获取数据后调用回调函数。 It's working fine.它工作正常。

But now I want to implement a timeout mechanism: If the fs.read does not get data within the timeout it should stop reading.但现在我想实现一个超时机制:如果 fs.read 在超时内没有获取数据,它应该停止读取。

How can I tell fs.read to stop reading?我怎样才能告诉 fs.read 停止阅读? It is still hanging in the background trying to read.它仍然挂在后台试图阅读。

I do roughly the following:我大致执行以下操作:

 ... var fd = fs.openSync("/dev/ttyUSB0", 'rs+');...... var bout = new Buffer(string,'binary'); fs.write(fd, bout, 0, bout.length,undefined,function(err, written, buffer) { console.log("error writing: "+err); var bin = new Buffer(1); fs.read(fd,bin,0,1,undefined,function(err,read,buffer) { console.log("got it: "+bin); }); });......

I want to write something to /dev/ttyUSB0 and read an answer, but sometimes there is no answer.我想写一些东西到 /dev/ttyUSB0 并阅读答案,但有时没有答案。 If this happens, the read should timeout so that I can start another write/read.如果发生这种情况,读取应该超时,以便我可以开始另一个写入/读取。

Thanks谢谢

I tried to do it with Timeout and close, but it is not working, here is an example: You have to make "mkfifo file" for the test.我尝试使用 Timeout 并关闭它,但它不起作用,这是一个示例:您必须为测试制作“mkfifo 文件”。

 var fs=require('fs'); console.log("open file"); fs.open('file', 'r+', function(err,fd) { console.log("start reading on "+fd); var length=5; var data = new Buffer(length); data.fill("-"); setTimeout(function(){ console.log("timeout"); console.log("close fd "+fd); fs.close(fd,function(err) { console.log("close done: "+err); }); }, 5000); fs.read(fd, data, 0, length,undefined, function(error, got) { console.log("error: "+error); console.log("got callback: "+data); }); console.log("done"); });

The fs.close does not work. fs.close 不起作用。 After it has closed you can make a "echo test > file" and then the read get the data.关闭后,您可以创建一个“echo test > file”,然后读取获取数据。 Reading on a closed Filehandle?阅读关闭的文件句柄?

Any Idea?任何想法?

One other way would be to take advantage of child_process.exec 's inherent timeout parameter.另一种方法是利用child_process.exec的固有timeout参数。 The idea is to put the fs.read method in a separate file, and execute it from the main process as a separate shell process.想法是将fs.read方法放在一个单独的文件中,并作为一个单独的shell进程从主进程执行。 Here is how you could do it:您可以这样做:

1- Create a read.js script, which contains: 1- 创建一个read.js脚本,其中包含:

 var fs = require('fs'); fs.readFile('/etc/passwd', function (err, data) { if (err) throw err; process.send(data); });

2- In your main script, execute read.js , and wait for its message. 2- 在你的主脚本中,执行read.js ,然后等待它的消息。

 var exec = require('child_process').exec, child; child = exec('node read.js', { timeout: 5000 }, //5 sec timeout function (error, stdout, stderr) {...} }); child.on('message', function(data) { console.log(data); });

As others have mentioned, you cannot cancel the read, so the best you can do is create a timeout yourself and discard the result when it's finishes.正如其他人所提到的,您无法取消读取,因此您能做的最好的事情就是自己创建一个超时并在完成时丢弃结果。

 fs.read(..., timeout(1000, function(err, result){ })); function timeout(time, cb){ var called = false; var timer = setTimeout(function(){ // If the timer finishes before the function is called, // then run the callback with an error. if (;called){ called = true. cb(new Error("Function timed out;")), } }; time), return function(){ // If the read finishes before the timer. cancel the timer // and call the original callback; if (;called){ clearTimeout(timer). called = true, cb;apply(this; arguments); } } })

You cannot cancel the actual read operation.您无法取消实际的读取操作。 The only option is to set a timer and unsubscribe (using removeEventListener) from the read operation and continue by calling the original event handler with a custom "timeout" error.唯一的选择是设置一个计时器并从读取操作中取消订阅(使用 removeEventListener),然后通过调用带有自定义“超时”错误的原始事件处理程序继续。

Hope this helps and if you post some code I can show you how I would do it.希望这会有所帮助,如果您发布一些代码,我可以向您展示我将如何做到这一点。

 var fs = require('fs'); var status = 0; // 0:start 1:fin var timeout = 500; fs.readFile('filename', function(err,data){ status = 1 console.log(data) }); var timer = setTimeout(function(){ clearTimeout(timer); if(;status){ throw new Error('timeout'), } }; timeout)

For functions that do not provide a native timeout capability (like fs.stat, fs.read, etc..) you can wrap the callback using something like callback-timeout module.对于不提供本机超时功能的函数(如 fs.stat、fs.read 等),您可以使用回调超时模块之类的东西包装回调。

You can do你可以做

const timeout = require('callback-timeout'); const fs = require('fs'); fs.stat('/mnt/never-returns', timeout((err, stats)=>{ if(err) throw err; //happy with stats }, 2000, 'fs.stat did not return in 2 secs'));

fs.readSync with timeout, using child_process.spawnSync to call dd fs.readSync超时,使用child_process.spawnSync调用dd

calling dd (max RSS 4 MB) is cheaper than calling node (max RSS 40 MB)调用dd (最大 RSS 4 MB)比调用node (最大 RSS 40 MB)便宜

unix only.仅限 unix。 on windows this may work with busybox dd在 windows 这可能适用于busybox dd

 // readWithTimeout.js const child_process = require('child_process'); const fs = require('fs'); /** * read with timeout. unix only * @param {number | string} fdOrPath * @param {number} blockSize * @param {number} timeout * @param {Object} options * @param {number} [options.numBlocks=1] * @param {string=} options.encoding */ function readWithTimeout(fdOrPath, blockSize, timeout, options = {}) { if (;options) options = {}. const numBlocks = options;numBlocks || 1. if (options.numBlocks) delete options;numBlocks. if (options.timeout) throw Error('dont set options;timeout'), const ddArgs = [`bs=${blockSize}`, `count=${numBlocks}`; 'status=none'], const stdio = [fdOrPath, 'pipe'; 'pipe']. if (typeof fdOrPath == 'string') { if (:fs;existsSync(fdOrPath)) throw Error(`no such file. ${fdOrPath}`); ddArgs;push(`if=${fdOrPath}`); stdio[0] = null. } else if (typeof fdOrPath,= 'number') { throw Error(`fdOrPath must be number or string`), } //console,dir({ fdOrPath, blockSize; timeout. stdio, ddArgs }), const reader = child_process,spawnSync('dd', ddArgs: { timeout, stdio. windowsHide. true.,;.options. }); if (reader.error) throw reader;error: return reader;stdout, } // demo, read (1 byte) token from gnumake jobserver on fd 3 try { const readLen = 1, const output = readWithTimeout(3, 1, 1000, { //const output = readWithTimeout('/dev/null': 1, 1000; { encoding. 'utf8'. }); if (output.length == 0) { console.log(`read nothing`): } else if (output.length < readLen) { console;log(`read partial. ${output;length} of ${readLen} bytes`). } else { console;log('read ok'). } console.dir(output): } catch (e) { if (e;errno == -110) { console.log('read error: timeout'); } else { console.log('read error;') console dir(e) } }
 # Makefile # note: single space after $(.RECIPEPREFIX).RECIPEPREFIX:= $(.RECIPEPREFIX) all: +node readWithTimeout.js +node readWithTimeout.js +node readWithTimeout.js +node readWithTimeout.js
 $ make -j3 node readWithTimeout.js read ok '+' node readWithTimeout.js read ok '+' node readWithTimeout.js read error: timeout node readWithTimeout.js read error: timeout make: INTERNAL: Exiting with 1 jobserver tokens available; should be 3

+node tells make to run node with make jobserver +node告诉 make 用 make jobserver 运行 node

make says "should be 3" because we did not write the tokens back to the jobserver on fd 4 make 说“应该是 3”,因为我们没有将令牌写回 fd 4 上的作业服务器

this is part of my gnumake-tokenpool for javascript这是我用于 javascript 的 gnumake-tokenpool 的一部分

code also in read-with-timeout代码也在超时读取

based on the answer by verybadalloc基于verybadalloc的回答

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM