拆分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
相关产品推荐
相关产品推荐

