You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:42:51