Node.js net.socket重复发送旧数据:如何清除套接字残留数据?
问题
我正在用Node.js为一款即将推出的游戏开发服务器,游戏客户端使用GML语言编写。我通过socket.write向客户端发送数据,但不希望新消息中包含之前socket.write写入的字符串。
例如:
socket.write("hello!");
客户端成功收到字符串"hello!"。
但再次调用socket.write时:
socket.write("hello again!");
客户端会收到字符串"hello!hello again!"。请问这是什么原因导致的?能否在再次调用socket.write前清除套接字中的残留信息?
服务器代码:
var net = require("net"); var port = 3000; var server = net.createServer(); let sockets = []; playerID = 0; server.on("connection",function(socket) { var addr = socket.remoteAddress; console.log("New Connection: " + addr); sockets.push(socket); playerID += 1; socket.ID = playerID; console.log(socket.ID); sockets.forEach((client) => { client.write("Player:Connected:" + socket.ID); console.log("Player:Connected:" + socket.ID); }); socket.on("data",function(data) { console.log("data: " + data); if (data.includes("Client:Disconnected")) { console.log(socket.remoteAddress + " has disconnected"); const index = sockets.indexOf(socket); if (index > -1) { sockets.splice(index, 1); //remove client from socket list } //Notify the other clients of the disconnect event sockets.forEach((socket) => { socket.write("Player:Disconnected:" + socket.ID); }); }; }); socket.once("closed",function() { console.log("Player Disconnected: " + addr); }); }); server.listen(port,function() { console.log("The Server has been Started on port " + port); });
我尝试过谷歌搜索该问题但没有结果,查阅文档也未找到相关信息。
解答
原因分析:Node.js的
net.Socket基于TCP协议,而TCP是字节流协议,它不会自动为消息划分边界。服务器多次调用socket.write发送的数据,会被TCP合并成连续字节流发送给客户端。如果客户端没有正确处理消息边界,就会把多次发送的数据当成一个完整消息接收,出现拼接情况。这不是服务器套接字有残留信息,是TCP的特性决定的。解决方法:需要自定义消息边界规则,让客户端能正确拆分每次的消息:
- 使用分隔符:每次发送消息时在结尾加特定分隔符(如
\n、|),比如服务器发送socket.write("hello!\n");,客户端接收时按分隔符拆分字符串,提取完整的单条消息。 - 固定消息长度:在每个消息前加固定长度的头部,标识后续消息的字节长度。比如先发送4字节的长度值,再发送对应长度的消息内容,客户端先读取长度,再读取对应字节数作为完整消息。
- 结构化数据格式:使用JSON等格式发送完整数据,客户端接收后解析成对象,推荐配合分隔符使用,避免部分JSON导致解析错误。
- 使用分隔符:每次发送消息时在结尾加特定分隔符(如
不存在“清除套接字残留信息”的操作,TCP套接字不会缓存未发送的残留数据(调用socket.write返回true后,数据已进入发送流程)。问题核心完全在消息边界处理上,和服务器端套接字状态无关。
内容的提问来源于stack exchange,提问作者Stefqnutz
相关产品推荐
相关产品推荐

