NodeJS中TCP套接字数据流15-20分钟后停止接收问题排查
data事件停止触发但连接未断开的问题 先把你的代码整理成可读性更强的版本(注意补充了net模块的引入,原代码里漏了):
const net = require('net'); const websock = net.createServer(function(sock) { sock.pipe(sock); sock.setEncoding('utf8'); sock.setKeepAlive(true); sock.on("data", function(d) { console.log("websock", d); }); sock.on('end', function() { console.log('websock disconnected'); }); }); websock.listen(777, '127.0.0.1');
结合你描述的现象——运行15-20分钟后data回调停止工作,连接没断开也没错误日志,大概率是以下几个原因导致的:
1. TCP背压导致流暂停
你用了sock.pipe(sock),这会把服务器收到的数据直接回写给客户端。如果客户端的接收速度跟不上服务器的回写速度,TCP的滑动窗口会逐渐缩小,直到服务器的发送缓冲区被填满。这时候Node.js的流会自动进入暂停模式,data事件会停止触发——因为底层已经没有空间接收新数据了,但连接本身还处于ESTABLISHED状态(没有FIN/RST包),所以不会触发end事件。加上你开启了TCP keepalive,连接会一直维持,看起来就像数据流“卡住”了。
2. UTF-8编码解析阻塞
你设置了sock.setEncoding('utf8'),Node.js会自动把收到的Buffer解析成UTF-8字符串。如果客户端发送的字节流中包含不完整的多字节UTF-8字符(比如数据包刚好截断了一个中文的字节),Node.js会暂时缓存这些不完整的字节,等待后续字节补全,这时候data事件就不会触发。如果客户端后续没补全这个字符,或者持续发送截断的字节,就会一直卡在这,data回调再也不执行。
3. 未监听error事件遗漏了隐藏错误
你的代码没有监听sock的error事件,有些非致命的TCP错误(比如数据包校验失败、重传超时但还没断开连接)不会直接触发end,但会导致流的状态异常,从而停止触发data事件。虽然Node.js默认会把未处理的error抛出导致进程崩溃,但如果你的进程用了某种错误捕获机制(比如全局uncaughtException),可能会把错误吞掉,导致你看不到任何日志。
解决建议
- 先移除
sock.pipe(sock)(如果不需要回写数据的话),或者处理流的背压:如果必须回写,监听drain事件,在缓冲区可用时再继续写,或者手动调用sock.pause()/sock.resume()控制流的状态。 - 暂时去掉
setEncoding('utf8'),先接收原始Buffer,自己处理编码逻辑,避免因为不完整的UTF-8字符阻塞data事件。 - 加上
error事件监听,排查是否有隐藏错误:sock.on('error', (err) => { console.error('Socket异常:', err); }); - 用
netstat -an | grep 777查看连接状态,确认是否处于ESTABLISHED且发送/接收缓冲区有积压;或者用tcpdump抓包,分析数据流的传输情况。
内容的提问来源于stack exchange,提问作者Murlidhar Fichadia




