Node.js客户端readline的close事件仅服务端CTRL-C时触发如何解决
问题根因
问题核心是TCP半关闭逻辑和readline流的触发条件不匹配:
- 客户端发送
quit\r\n后会主动关闭自身写端,向服务端发送FIN包,触发服务端的end事件,但此时服务端没有主动回发FIN包,客户端的socket可读端始终处于开启状态。 - 客户端的
readline实例绑定socket为输入源,只有当输入流完全结束(收到FIN包且缓冲区数据全部处理完成)时才会触发close事件,你手动停止服务端时操作系统会主动给所有存活连接发FIN,因此客户端可以正常触发事件。 - 你此前将
socket.destroy()写在end/close回调中属于无效调用:这两个事件本身就是连接进入关闭流程才会触发的回调,此时调用销毁逻辑完全没有作用,发送EOT字符也只会被readline识别为普通文本,不会触发流结束。
解决方案
调整服务端逻辑,在收到客户端的quit指令完成业务处理后,主动调用socket.end()回发FIN包即可:
const net = require('net'); const server = net.createServer((socket) => { const remoteAddress = socket.remoteAddress; // 新增data事件监听处理客户端指令 socket.on('data', (buffer) => { const content = buffer.toString().trim(); if (content === 'quit') { // 若有需要返回给客户端的业务数据,请先写入socket,确认写入完成再调用end // 示例:socket.write('业务返回结果\r\n', () => socket.end()) socket.end(); // 兜底逻辑:100ms后如果连接未销毁则强制关闭,避免半连接残留 setTimeout(() => !socket.destroyed && socket.destroy(), 100); } }); socket.once("close", function () { console.log("Connection from %s closed", remoteAddress); }); socket.once("end", function() { console.log("Ending connection"); }); });
调用socket.end()后服务端会主动向客户端发送FIN包,客户端socket可读端检测到流结束后会触发readline的close事件,无需修改任何客户端代码即可实现需求。
内容的提问来源于stack exchange,提问作者david3123
相关产品推荐
相关产品推荐

