You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

NodeJS中TCP套接字数据流15-20分钟后停止接收问题排查

分析Node.js TCP服务器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事件遗漏了隐藏错误

你的代码没有监听sockerror事件,有些非致命的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

火山引擎 最新活动