Haxe服务端Socket连接后阻塞,无法接收客户端消息
问题
使用Haxe的sys.net.Socket编写服务端,客户端可成功建立连接,但为客户端启动处理线程后,程序卡在接收消息的代码行,无论客户端发送什么数据都无法响应。
服务端代码
package; import sys.net.Host; import sys.net.Socket; import sys.io.File; import haxe.xml.Access; import sys.thread.Thread; class Player { public var socket:Socket; public var name:String; public var server:Server; public var active:Bool; public function new(sv:Server, skt:Socket) { server = sv; socket = skt; name = ''; active = true; } public function toString():String { var peer = socket.peer(); var pstr = Std.string(peer.host) + ':' + peer.port; return (name == null || name == '') ? pstr : (name + '(' + pstr + ')'); } public function send(text:String) { try { socket.output.writeString(text); socket.output.flush(); // 新增:确保数据立即发送 } catch (z:Dynamic) { trace(z); active = false; } } } class Server { var socket:Socket; var ip:String; var port:Int; var players:Array<Player> = []; public function new() { var config:Access = new Access(Xml.parse(File.getContent("config.xml"))); var netCfg = config.node.cfg.node.connection; ip = netCfg.att.ip; port = Std.parseInt(netCfg.att.port); socket = new Socket(); socket.bind(new Host(ip), port); trace("Starting server..."); socket.listen(4); trace("Server started."); accept(); } public function handleClient(player:Player):Void { trace("handle client thread brrr"); try { while (player.active) { var msg:String = player.socket.input.readLine(); // 修改:按行读取消息,匹配客户端逻辑 if (msg == null) break; // 连接关闭时readLine返回null trace(msg); if (msg == "disconnect") { break; } } } catch (e:Dynamic) { trace(e); } finally { // 统一处理断开逻辑,确保循环退出后执行 trace(Std.string(player) + " disconnected"); players.remove(player); try { player.socket.shutdown(true, true); player.socket.close(); } catch (e:Dynamic) { trace(e); } player.active = false; } } public function accept():Void { trace("Listening for connections on " + ip + ":" + port); while (true) { var client = socket.accept(); if (client != null) { trace("A new client has connected [" + client.peer().host + "]"); var player = new Player(this, client); players.push(player); Thread.create(() -> handleClient(player)); } } } public static function main() { new Server(); } }
客户端代码
package; import haxe.io.Encoding; import sys.net.Host; import sys.net.Socket; import sys.thread.Thread; class Client { var socket:Socket; public function new(ip:String, port:Int):Void { socket = new Socket(); socket.connect(new Host(ip), port); Thread.create(() -> listen()); } function listen():Void { while (true) { try { var msg:String = socket.input.readLine(); if (msg == null) break; trace(msg); } catch (e:Dynamic) { trace("Connection lost. [" + e + "]"); break; } } } public function send(data:String):Void { socket.output.writeString(data + "\n", Encoding.UTF8); // 新增:添加换行符,作为消息边界 socket.output.flush(); // 新增:刷新缓冲区,确保数据立即发送 } }
问题原因及修复说明
- 读取方式错误:原服务端使用
socket.read(),该方法会持续读取直到客户端关闭连接,导致线程永久阻塞。改为socket.input.readLine(),按行读取单条消息,匹配客户端的消息发送逻辑。 - 缓冲区未刷新:客户端发送数据后,数据可能滞留在系统缓冲区未实际发送,添加
socket.output.flush()确保数据立即传输到服务端。 - 断开逻辑位置错误:原服务端的断开清理代码在while循环内部,导致每次循环都会执行错误的断开操作。将这部分逻辑移到
finally块,确保只有在连接断开或退出循环时才执行清理。 - 消息边界缺失:客户端发送消息时添加换行符
\n,服务端通过readLine()识别消息结束,确保能正确解析单条消息。
内容的提问来源于stack exchange,提问作者feweks
相关产品推荐
相关产品推荐

