NodeJS net.Socket客户端:已写入数据却无响应意外关闭连接
Socket连接写入后未收到响应意外关闭的问题排查
背景
我在公司开发了一个小型程序,用于与PLC上的服务器Socket建立连接,程序工作流程如下:
- 每10秒与服务器建立新的Socket连接
- 客户端程序与PLC上的服务器Socket建立连接
- 连接初始化完成后立即写入数据
- 服务器Socket响应写入请求并返回数据
- 收到服务器响应后关闭Socket连接
无论写入成功、服务器返回空响应、出现错误或超时,我都会将连接开始时间、写入时间、服务器响应时间、写入帧、服务器返回帧等信息记录到数据库中。我使用NodeJS原生模块net.Socket来定义客户端Socket,并管理服务器响应、错误及超时。
代码
"use strict"; const net = require('net'), {convertToHex} = require("./services/utils"), {db_insert} = require("./services/db_query"), {log_socket_client} = require("./services/logger"), crypto = require("crypto"), cmdCommandList = {/* ... */}; let timeout_interval_socket_client = setInterval( () => { let socket_client = new net.Socket(); socket_client.uuid = crypto.randomUUID(); const date_start_task = new Date(); let frame_input_in_hex = null, date_socket_write = null; socket_client .on("connect", function() { buf_command_automat = /* _AUTOMATE_BUFFER_COMMAND_ */; frame_input_in_hex = convertToHex(buf_command_automat); socket_client.write(buf_command_automat, function() { date_socket_write = new Date(); }); }) .on('data', function(message) { /* INSERT TO BDD MESSAGE : frame output received by socket server */ socket_client.destroy(); }) .on('close', function(hadError) { (async() => { if(socket_client.bytesWritten === 0) { /* INSERT TO BDD MESSAGE : noBytesWritten */ } if(socket_client.bytesRead === 0) { /* INSERT TO BDD MESSAGE : no packet received */ } await socket_client.destroy(); })(); }) .on('error', function(error) { /* INSERT TO BDD error.toString() */ if(socket_client) socket_client.close(); }) .on('timeout', () => { /* INSERT TO BDD MESSAGE : timeout */ if(socket_client) socket_client.close(); }); socket_client.setTimeout(15000); socket_client.connect(/* _AUTOMATE_PORT_ */, /* _AUTOMATE_IP_ */); }, (10000) ); process.on('SIGINT', () => { if(timeout_interval_socket_client) { clearInterval(timeout_interval_socket_client); } });
问题
当前遇到的问题是:部分连接在已完成客户端Socket写入操作的情况下,未收到服务器响应就意外关闭了。请问可能的原因是什么?
已尝试的解决措施
- 排查是否为动态关闭的Socket
- 尝试用
.destroy()替代.close()关闭Socket - 为Socket添加ID,排查是否为
setInterval的副作用
补充信息
- NodeJS版本:v18.17.1
- npm版本:v9.6.7
- Socket超时设置为15秒
可能的原因分析
1. PLC服务器端限制
PLC的Socket服务器可能存在连接数上限、请求频率限制,或内部资源不足,导致接收写入后主动关闭连接而不返回响应。比如部分PLC对并发连接或每秒请求数有严格限制,若程序每10秒发起一次连接,服务器端未正确处理旧连接残留时,可能触发保护机制直接断开连接。
2. 网络层面问题
- 中间设备规则拦截:交换机、防火墙等中间设备可能设置了短于15秒的空闲超时,或对特定数据包内容进行过滤,导致服务器响应无法到达客户端,连接被强制关闭。
- 数据包丢失:写入的请求成功到达服务器,但服务器的响应在传输过程中丢失,客户端未收到数据,最终触发超时或连接被动关闭。
3. Node.js Socket处理逻辑缺陷
- 重复销毁Socket:
close事件回调中重复调用destroy(),而close事件本身就是连接关闭时触发,重复销毁会导致异常状态;同时回调中的await无实际作用(Node.js事件回调不等待异步操作),可能引发资源泄漏。 - 超时逻辑冲突:
setTimeout(15000)设置的是Socket空闲超时,若服务器处理请求的时间接近15秒,可能在响应发出前触发超时,客户端主动关闭连接,此时服务器的响应可能还在传输中,但客户端已无法接收。 - 写入完成的判断偏差:
socket_client.write的回调仅表示数据写入操作系统发送缓冲区,不代表数据已成功发送到服务器。若此时网络异常,数据未到达服务器就被断开连接,客户端会误以为写入完成,但服务器实际未收到完整请求。
4. 数据帧格式错误
写入PLC的buf_command_automat可能存在格式问题,比如校验位错误、帧长度不符合协议要求,PLC服务器接收到后无法解析,会直接关闭连接而不返回响应。
5. 资源泄漏累积
虽然调用了destroy()或close(),但部分Socket在错误或超时后未彻底释放资源,累积后导致后续连接出现异常关闭的情况。
内容的提问来源于stack exchange,提问作者Mathieu
相关产品推荐
相关产品推荐

