大概目前是这个情况,socket.io
监听某个事件,回调函数是读取一个文件中的1024B,全部都用的是同一个 Buffer
var f1 = fs.openSync(path.join(path.dirname(__dirname), 'Advice.mp3'), 'r');
var bf1 = Buffer(1024);
socket.on('receive', function(msg){
fs.read(f1, bf1, 0, 1024, msg.index * 1024, function(err, bytesRead, data){
socket.emit('send_block', data);
});
});
这个receive
事件会被频繁调用,可能20ms一次。之后我发现读几万个块,其中总有几个块的内容不对,就是说和原始文件中的不同,而其它的块则没有问题。我排查了很久才发现是这里出了问题,改成readSync
之后,读到的块就都是对的了(当然我也知道用同步肯定是不合适的)。
我的问题有两个
- 为什么会有这种情况,写 buffer 并不是原子操作?
- 如果我不想每次都开一个新的 buffer,而是想尽可能重复利用一个 Buffer,又要异步读,有什么好办法吗?(之前试过random-access-file,也遇到一样的问题)
谢谢
13 回复
。。。理论上,整个代码都是单线程的,是否“原子操作”其实不重要。。。
我觉得你可能出错的地方: 1、认为每次读肯定会把Buffer读满,于是没有用上 bytesRead 2、认为socket发送buffer必定会一次性发送掉全部指定的长度,其实不一定…
试试这个,自己写的话需要控制drain事件 还有pause resume等
socket.pipe(fs.createWriteStream(path.join(path.dirname(__dirname), 'Advice.mp3')));
btw 好像__dirname自动触发编辑器的"B"
myy说的是对的。 你new Buffer(1024)时,这1024个字节中是有随机数值的。 当一个mp3是1025个字节时,也许第一次正好读取1024个字节,正好覆盖掉你的bf1,当第二次读取时,实际只有第一个字节是mp3的第1025个字节, 其余的字节数是上一次读取时的数据,所以不正确。
@myy 我不太确定这里是不是好用pipe,实际中的代码这一句socket.emit('send_block', data);
中的data是一个包含了data的Object,例如{content: data, a: xxx, b: xxx}
,如果直接只是把data发出去大概可以pipe