我目前正在开发我的第一个C#项目,它是一个聊天室应用程序,使用C# Win Forms和.NET 7.0。用户可以创建一个聊天室并作为服务器,或者只是加入另一个聊天室。对于通信,我使用socket类。
我开始建立一个项目,但现在的要求是有两个独立的项目,可以单独运行。现在我有3个项目在我的解决方案中,一个是合并的,另外两个是客户端和服务器的独立项目。组合解决方案按预期工作,服务器项目也是如此,但客户端项目崩溃而没有抛出异常。这是完全相同的代码,我不明白为什么一个运行良好,而另一个只是关闭。
我想我可以确定导致崩溃的代码行,或者至少这是我在调试器中按F10遍历每一行代码时可以转到的最后一行代码。当我到达这一行并按F10转到下一行时,应用程序关闭。
第一个月
这行代码位于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冻结,而我们等待一个消息。Tasks将建议线程池使用任何线程,直到它命中await,并在await结果出现后继续使用任何线程。如果我不使用任务,我的应用程序将冻结,而我等待一个消息。
我不太确定,但我的头脑告诉我,这可能是一个发生在不同线程中的未处理异常,如果这有意义的话?
我试图用这个异常处理程序捕获任何东西:
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());
}
型
但这并没有帮助,应用程序只是关闭,控制台中没有错误消息。
我还发现了一件事:我第一次点击我们谈论的var amountBytes = await _clientSocket.ReceiveAsync(bytes);
这一行时,它成功地接收了数据。在此之后,套接字的connected属性将更改为false。我确实读到过这方面的内容,从我所读到的内容来看,connected属性表示套接字的最后一个状态,并且是不可删除的。这让我很困惑,因为我刚刚成功地收到了一些东西,然后它就变成了false。
我在这个问题上坐了好几天了,我在任何地方都找不到解决办法,因为我的问题似乎太特殊了。
我的胃告诉我这与多线程有关,但这可能是错误的,我是一个初学者...
我很感激任何帮助,不管是什么。先谢了。
编辑:我也试图在任务开始时删除if(socket.connected)条件,但没有做任何事情。
Edit 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()
,并设置应用程序不应该在mainForm关闭时关闭的设置,而是在最后一个Form关闭时关闭。
1条答案
按热度按时间jq6vz3qz1#
我找到了解决办法,这是完全不同的东西!
我使用的是win窗体,另一个窗体(主窗体)调用了当前窗体,当新窗体成功打开时,我的代码会被load方法自动执行。我在前一个窗体上使用了this.Close(),所以我的新窗体在很短的时间后就关闭了,我认为是我的代码导致了这一点。我把这一行改成了.Hide(),现在它可以工作了。我想如果我把它改回this.Close()并设置应用程序不应该在mainForm关闭时关闭的设置,而是在最后一个Form关闭时关闭的设置,这是明智的。