Node.js ws库createWebSocketStream关闭不关闭底层WebSocket连接问题
问题1:关闭双工流就关闭WebSocket连接是否为设计预期
是,ws库的createWebSocketStream设计上就是和底层WebSocket连接1:1绑定的,双工流的生命周期完全对应底层连接的生命周期,调用duplex.end()默认会主动关闭底层WebSocket连接,所以无法在同一个持久化WebSocket连接上创建多个独立的createWebSocketStream实例,这个是官方的设计逻辑。
问题2:为什么close事件没有触发
有两个常见原因:
- 只有创建
WebSocketStream的时候显式传入{ emitClose: true }配置,才会触发close事件,你当前只有客户端加了这个配置,服务端创建实例的时候没有添加 - 你手动监听
data事件写数据的逻辑没有处理流的结束通知,默认情况下只有底层WebSocket连接完全关闭的时候,才会触发WebSocketStream的close事件
解决方案
如果你需要复用同一个WebSocket连接传输多个文件/多个独立流,不能直接用原生的createWebSocketStream,需要自己在WebSocket上层实现多路复用逻辑:比如给每个传输的数据包加流ID、类型标识(数据帧/结束帧),自行区分不同的流,再基于这个逻辑封装上层的双工流,就可以在同一个连接上同时跑多个独立的流。
如果暂时不需要复用连接,只是要修复当前的事件触发问题,可以按如下方式修改代码:
修复后的服务端代码
//server.js const WebSocket = require('ws'); const fs = require('fs'); const wsserver = new WebSocket.Server({ port: 8080 }); wsserver.on('connection', function connection(ws) { console.log("client connected"); // 每个连接创建独立的写入流,避免多个客户端写入同一个文件出现内容错乱 const destinationFileStream = fs.createWriteStream('./bar'); // 补充emitClose配置 const duplex = WebSocket.createWebSocketStream(ws, { emitClose: true }); // 直接用pipe自动处理数据写入、背压、流结束逻辑,不需要手动监听data事件写数据 duplex.pipe(destinationFileStream); duplex.on('close', function(){ console.log("the duplex channel has closed") }); destinationFileStream.on('close', function(){ console.log("file has been written successfully") }) });
修复后的客户端代码
//client.js const WebSocket = require('ws'); const fs = require('fs'); const readFileStream = fs.createReadStream('/home/ubuntu/Downloads/atom-amd64.deb') const wsstream = new WebSocket('ws://localhost:8080'); wsstream.on('open', function(){ const duplex = WebSocket.createWebSocketStream(wsstream, { emitClose: true }); // 用pipe自动处理读、写、流结束逻辑 readFileStream.pipe(duplex); readFileStream.on('close', function(){ console.log("file has been read successfully") }); duplex.on('close', function(){ console.log("the duplex channel has closed") }); wsstream.on('close', function(){ console.log("the wsstream has closed") }); });
内容的提问来源于stack exchange,提问作者n-bs-p
相关产品推荐
相关产品推荐

