Node.js Net Socket连接未正常关闭,后续连接无响应问题求助
Node.js TCP Socket连接未正常关闭导致后续请求无响应问题
编写Node.js TCP服务器时遇到问题:客户端或服务器未真正关闭Socket连接,导致服务器对后续连接无响应。客户端发送第二次请求后挂起,服务器未进入socket.on('data' ...)监听器。
服务端代码(server.js)
const net = require('net'); const serverAddress = '127.0.0.1'; // Replace with the actual server address const serverPort = 3000; // Replace with the actual server port const server = net.createServer(socket => { socket.on('data', data => { console.log('Received request: ', data.toString()) socket.write('Hi, this is server response'); }); socket.on('close', () => { socket.end(); socket.destroy(); console.log('Connection closed'); }); socket.on('end', () => { console.log('Connection end'); socket.end(); }); socket.on('error', error => { console.error('Socket error:', error); }); }); server.listen(serverPort, serverAddress, () => { console.log(`Server listening on ${serverAddress}:${serverPort}`); });
客户端代码(client.js)
const net = require('net'); const serverAddress = '127.0.0.1'; // Replace with the actual server address const serverPort = 3000; // Replace with the actual server port const client = net.createConnection(serverPort, serverAddress, () => { console.log('Connected to the server'); let msg = 'First request'; client.write(msg); console.log("Sent2 to server:", msg) client.on('data', data => { console.log('Server response:', data.toString()); client.end(); }); client.on('close', () => { console.log('Connection closed'); }); client.on('end', async () => { console.log('Connection end'); setTimeout(runSecondConnection, 3000); }); }); function runSecondConnection() { let client2 = net.createConnection(serverPort, serverAddress, () => { console.log('Connected2 to the server'); let msg = 'Second request'; client.write(msg); console.log("Sent2 to server:", msg) }) client2.on('data', data => { console.log('Server2 response:', data.toString()); client.end(); }); client2.on('close', () => { console.log('Connection2 closed'); }); client2.on('end', () => { console.log('Connection2 end'); }); }
实际运行结果
服务器输出
Received request: First request Connection end Connection closed
客户端输出
Connected to the server Sent2 to server: First request Server response: Hi, this is server response Connection end Connection closed Connected2 to the server Sent2 to server: Second request
预期运行结果
服务器输出
Received request: First request Connection end Connection closed Received request: Second request Connection end Connection closed
客户端输出
Connected to the server Sent2 to server: First request Server response: Hi, this is server response Connection end Connection closed Connected2 to the server Sent2 to server: Second request Server response: Hi, this is server response Connection end Connection closed
额外现象
当客户端挂起时终止脚本,服务器会打印错误并再次输出"Connection closed":
Server listening on 127.0.0.1:3000 Received request: First request Connection end Connection closed Socket error: Error: read ECONNRESET at TCP.onStreamRead (node:internal/stream_base_commons:220:20) { errno: -4077, code: 'ECONNRESET', syscall: 'read' } Connection closed
问题
为何错误后会出现"Connection closed"消息?是存在两个连接吗?还是第一次的Connection closed并未真正关闭连接?
问题根源与修复方案
- 客户端核心错误
在runSecondConnection函数中,发送第二次请求时错误使用了第一个客户端的client对象,而非新创建的client2:
// 错误代码 client.write(msg); // 正确代码 client2.write(msg);
这导致第二次请求根本没有通过新连接发送到服务器,客户端2一直等待响应,因此出现挂起现象。
- 服务器端冗余操作清理
socket.on('close')中调用socket.end()和socket.destroy()完全多余,close事件触发时连接已经处于关闭状态,这些操作不会产生任何效果。socket.on('end')中调用socket.end()属于重复操作,end事件本身就是对方调用end()后触发的,此时socket已经进入关闭流程。
简化后的服务器端代码:
const net = require('net'); const serverAddress = '127.0.0.1'; const serverPort = 3000; const server = net.createServer(socket => { socket.on('data', data => { console.log('Received request: ', data.toString()) socket.write('Hi, this is server response'); }); socket.on('close', () => { console.log('Connection closed'); }); socket.on('end', () => { console.log('Connection end'); }); socket.on('error', error => { console.error('Socket error:', error); }); }); server.listen(serverPort, serverAddress, () => { console.log(`Server listening on ${serverAddress}:${serverPort}`); });
- 错误后二次打印Connection closed的原因
当终止挂起的客户端脚本时,第一个客户端连接因强制退出触发服务器端socket的ECONNRESET错误(表示连接被对方强制重置),而socket在触发error事件后会自动触发close事件,因此会再次打印"Connection closed"。这并非存在两个未关闭的连接,而是第一个连接的错误处理流程触发了第二次close事件。
内容的提问来源于stack exchange,提问作者Andrey Fedotov
相关产品推荐
相关产品推荐

