提问人:Ango619 提问时间:7/5/2023 最后编辑:Ango619 更新时间:7/6/2023 访问量:53
将我的 c# 项目拆分为两个单独的项目后,一个项目崩溃了,没有任何例外。可能与不同的线程有关?
After spliting my c# project into two seperate projects, one project crashes without any exception. Might have something to do with different threads?
问:
我目前正在开发我的第一个 c# 项目,它是一个聊天室应用程序,采用 .net 7.0 的 c# win 表单。 用户可以创建聊天室并充当服务器,也可以直接加入另一个聊天室。 对于通信,我使用套接字类。
我开始构建一个项目,但现在要求有两个独立的项目,可以单独运行。 现在我的解决方案中有 3 个项目,一个是组合项目,另外两个是客户端和服务器的单独项目。 组合解决方案按预期工作,服务器项目也是如此,但客户端项目崩溃而不引发异常。 它是完全相同的代码,我不明白为什么一个运行良好,而另一个只是关闭。
我想我可以识别导致崩溃的代码行,或者至少这是我在按 F10 浏览调试器中的每一行代码时可以转到的最后一行代码。 当我到达这一行并按 F10 转到下一行时,应用程序关闭。
var amountBytes = await _clientSocket.ReceiveAsync(bytes);
这行代码位于 try 块内,我没有到达 catch 块,应用程序只是关闭。while 循环的第一次遍历和 ReceiveAsync() 是成功的,在 while 循环的第二轮中,它会在该行崩溃。但它只在单独的客户端项目中这样做,而不是在完全相同代码的组合项目中这样做。
代码行位于我编写的通过套接字接收消息的任务中,这是整个任务,代码行位于任务的开头。
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;
}
}
}
}
我是初学者,所以让我解释一下我的思维过程: 我使用了一个任务,因为我不希望 UI 在我们等待消息时冻结。任务将建议线程池使用任何线程 is whishes 工作,直到它命中 await,并在 await 结果出现后使用任何线程 is whishes 恢复。如果我不使用任务,我的应用程序将在我等待消息时冻结。
我绝对不确定,但我脑海中的某些东西告诉我,这可能是在不同的线程中发生的未经处理的异常,如果这有意义的话?
我试图用这个异常处理程序捕获任何内容:
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());
}
但这无济于事,应用程序只是关闭,控制台中没有错误消息。
我发现的另一件事:
我第一次上线时,我们谈论它成功地接收了数据。
紧接着,套接字的 connected 属性更改为 false。
我确实读过这方面的内容,从我所读到的内容来看,连接属性表示套接字的最后状态,并且是不可识别的。这让我感到困惑,因为我刚刚成功收到了一些东西,然后它变成了假的。var amountBytes = await _clientSocket.ReceiveAsync(bytes);
我已经在这个问题上坐了好几天了,我在任何地方都找不到解决方案,因为我的问题似乎很特别。
我的肚子告诉我它与多个线程有关,但这可能是错误的,我是初学者......
无论是什么,我都会不胜感激。 提前致谢。
编辑:我还尝试在任务开始时删除if(socket.connected)条件,但没有做任何事情。
编辑2:一位社区成员要求提供调用ReceiveMessageAsync()的方法,所以我在这里添加它:
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();
}
}
编辑:我找到了解决方案,这是其他东西!
我使用的是 win 表单,另一个表单(这是主表单)称为当前表单,当新表单成功打开时,我的代码由 load 方法自动执行。
我在以前的表单上使用,所以我的新表单在很短的时间内就被关闭了,我认为我的代码导致了这种情况。
我把这条线改成了,现在它工作了。我想如果我将其改回并设置应用程序不应在主窗体关闭时关闭,而是在最后一个窗体关闭时关闭的设置,这是明智的。this.Close()
this.Hide()
this.Close()
答:
我找到了解决方案,这是别的东西!
我使用的是 win 表单,另一个表单(这是主表单)称为当前表单,当新表单成功打开时,我的代码由 load 方法自动执行。我正在使用这个。Close(),所以我的新表单在很短的时间内就被关闭了,我认为我的代码导致了这种情况。我把行改成了这个。Hide(),现在它工作了。我想如果我把它改回这个是明智的。Close() 并设置应用程序不应在 mainForm 关闭时关闭的设置,而是在最后一个 Form 关闭时关闭。
评论
var amountBytes = await _clientSocket.ReceiveAsync(bytes);
SetStatusToDisconnected();
private async Task ReceiveMessagesAsync()
break;
while
break;
break;
while