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

拆分C# WinForms聊天项目后客户端无异常崩溃求助

.NET 7 WinForms聊天室客户端崩溃问题排查与解决

问题背景

开发基于.NET 7.0的C# WinForms聊天室应用,支持用户创建房间作为服务器或加入他人房间,采用Socket类实现通信。最初为单项目结构,现拆分出独立运行的客户端和服务器项目,当前解决方案包含三个项目:原合并项目、独立服务器项目、独立客户端项目。其中合并项目与服务器项目运行正常,但独立客户端项目无任何异常抛出直接崩溃。

崩溃现象

调试定位到疑似崩溃代码行:var amountBytes = await _clientSocket.ReceiveAsync(bytes);,该行位于try块内但未进入catch块。循环首次执行ReceiveAsync成功,第二次执行时应用直接关闭,且仅在独立客户端项目中出现此问题。

排查过程

  • 怀疑是多线程中未捕获的异常导致问题,添加未处理异常处理器,但未生效,控制台无错误输出
  • 发现首次执行ReceiveAsync成功后,Socket的Connected属性变为false,了解到该属性仅代表上次通信状态,不可靠,但问题依旧存在
  • 移除任务开头的if(_clientSocket != null && _clientSocket.Connected)条件,问题仍未解决

相关代码片段

接收Socket消息的异步任务

private async Task ReceiveMessagesAsync()
{
    Byte[] bytes = new byte[1024];
    while (true)
    {
        if (_clientSocket != null && _clientSocket.Connected)
        {
            try
            {
                //Receive
                var amountBytes = await _clientSocket.ReceiveAsync(bytes);

                //If Server closes, we get a nullbyte
                if (amountBytes == 0)
                {
                    //UI
                    SetStatusToDisconnected();
                    HideOwnNameLabel();
                    DisplayNotification("Server wurde geschlossen");

                    break;
                }

                string decodedMessage = Encoding.UTF8.GetString(bytes, 0, amountBytes);

                //If we receive a message
                if (decodedMessage.StartsWith(_messageIdentifyer))
                {
                    string message = decodedMessage.Substring(_messageIdentifyer.Length);
                    //Prepare the datamodel
                    DataModel? messageModel = JsonSerializer.Deserialize<DataModel>(message);
  
                    if (messageModel != null)
                    {
                        DisplayMessage(messageModel);
                    }
                }

                //If we receive the userlist
                if (decodedMessage.StartsWith(_listIdentifyer))
                {
                    _usersDictionary.Clear();

                    //Convert the long string to an Array
                    string[] tempArray = decodedMessage.Split(new[] { _listIdentifyer }, StringSplitOptions.RemoveEmptyEntries);
                    string username = "";
                    int clientID = 0;
                    //we go through the loop with i +=2, since two following array item represent a single user.
                    for (int i = 0; i < tempArray.Length; i += 2)
                    {
                        clientID = Convert.ToInt32(tempArray[i]);
                        username = tempArray[i + 1];
                        //Dont add myself to the userlist
                        if (clientID != _personalId)
                        {
                            _usersDictionary.Add(clientID, username);
                        }
                    }
                    //UI
                    DisplayOnlineClients();
                    PopulateListBox();
                }
            }
            catch (Exception ex)
            {

                Console.WriteLine($"Client [{_personalId}]" + ex.Message);
                //UI
                DisplayNotification("Verbindung zum Server verloren");
                HideOwnNameLabel();
                SetStatusToDisconnected();
                break;
            }
        }
    }
}

添加的未处理异常处理器

static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
    Exception exception = (Exception)e.ExceptionObject;

    // Log or handle the exception here
    Console.WriteLine("Unhandled Exception:");
    Console.WriteLine(exception.ToString());

}

调用ReceiveMessagesAsync的ConnectAsync方法

public async Task ConnectAsync(string ipadress)
{
    _clientForm.NotificationTextbox.Clear();

    try
    {
        //Create endpoint and socket
        _clientEndpoint = new IPEndPoint(IPAddress.Parse(ipadress), _port);
        _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        //Connect
        await _clientSocket.ConnectAsync(_clientEndpoint!);

        byte[] tempbytes = new byte[1024];

        //Wait for ID from Server
        var receivedData = await _clientSocket.ReceiveAsync(tempbytes);

        string messageString = Encoding.UTF8.GetString(tempbytes, 0, receivedData);

        //Check if receivedData is indeed the ID
        if (messageString.StartsWith(_IDIdentifyer))
        {

            string[] parts = messageString.Split(new string[] { _IDIdentifyer }, StringSplitOptions.RemoveEmptyEntries);
            _personalId = Convert.ToInt32(parts[0]);
            Console.WriteLine("Client hat ID erhalten:" + _personalId);

            //Send own Nickname to the Server                    
            tempbytes = Encoding.UTF8.GetBytes(_nicknameIdentifyer + _nickname!);
            await _clientSocket.SendAsync(tempbytes);

            //UI
            SetStatusToConnected();
            ConnectButtonLogic();
            DisplayOwnName();

            //Connection established now, received messages get handled in Task ReceiveMessages
            _ = ReceiveMessagesAsync();
        }
        else
        {
            Console.WriteLine("Failed to receive ID");
            //UI
            DisplayNotification("Konnte ID nicht beziehen, versuchen Sie es erneut.");
            SetStatusToDisconnected();
            HideOwnNameLabel();
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        //UI
        SetStatusToDisconnected();
        HideOwnNameLabel();
    }
}

最终解决方案

问题根源在于WinForms中主窗体打开客户端窗体后执行了this.Close(),导致客户端窗体被关闭。将该行改为this.Hide()后问题解决,后续可改为this.Close()并设置应用在最后一个窗体关闭时再退出。


内容的提问来源于stack exchange,提问作者Ango619

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 06:22:03