zur Zeit arbeite ich an einem einfachen Client-Server-Chat-Programm (wollte in Client-Server Kommunikation Dinge in C#). Es funktioniert soweit bis auf die ordnungsgemäße Trennung vom Server.Probleme mit dem Schließen von TcpClient und NetworkStream
Auf dem Client ich hier diesen Code verwenden, um die Verbindung zu schließen:
client.Client.Disconnect(false); // client is the TcpClient
client.Close();
Auf dem Server eine Gewindeschleife dort für Nachrichten vom Client wartet:
private void StartChat()
{
int requestCount = 0;
byte[] bytesFrom = new byte[10025];
string dataFromClient = null;
string rCount = null;
while (true)
{
try
{
requestCount++;
NetworkStream stream = tcpClient.GetStream();
int bufferSize = (int)tcpClient.ReceiveBufferSize;
if (bufferSize > bytesFrom.Length)
{
bufferSize = bytesFrom.Length;
}
stream.Read(bytesFrom, 0, bufferSize);
dataFromClient = System.Text.Encoding.UTF8.GetString(bytesFrom);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$"));
rCount = Convert.ToString(requestCount);
string message = client.Name + " says: " + dataFromClient;
program.Broadcast(message);
}
catch(Exception ex) when (ex is ObjectDisposedException || ex is InvalidOperationException || ex is System.IO.IOException)
{
program.UserDisconnected(client);
break;
}
catch(ArgumentOutOfRangeException ex)
{
Debug.WriteLine(ex.ToString());
break;
}
catch(Exception ex)
{
Debug.WriteLine(ex.ToString());
break;
}
}
Wenn der Client die Verbindung trennt Mit dem oben gezeigten Code holt die Funktion den Strom die ganze Zeit und erzeugt eine solche Ausgabe:
\0\0\0\0\0\0\0 [and so on]
In diesem Fall wird die ArgumentOutOfRangeException
ausgelöst, da es keinen Index von $
gibt. Ich habe eine break
hinzugefügt, um die endlose Ausführung der Schleife zu vermeiden.
Überraschenderweise wird die ObjectDisposedException
nicht geworfen werden. Auch die System.IO.IOException
wird nicht geworfen, aber es sollte, weil der Stream geschlossen wurde, so dass die Verbindung verweigert wurde.
Wenn ich die Client-Anwendung nur schließen, die mit dem Server verbunden ist, der Server die Schleife nicht beendet, es wartet nur für einen Strom, der nie kommen wird, weil der Client getrennt.
Wie kann ich feststellen, ob der Client nicht mehr verbunden ist oder nicht mehr erreichbar ist? Und wie schließe ich die Client-Verbindung ordnungsgemäß, um eine Verbindung zu schließen?
Danke für Ihre Hilfe!
Update:
private void StartChat()
{
int requestCount = 0;
byte[] bytesFrom = new byte[10025];
string dataFromClient = null;
string rCount = null;
while (true)
{
try
{
requestCount++;
NetworkStream stream = tcpClient.GetStream();
stream.ReadTimeout = 4000;
int bufferSize = (int)tcpClient.ReceiveBufferSize;
if (bufferSize > bytesFrom.Length)
{
bufferSize = bytesFrom.Length;
}
// Wait for a client message. If no message is recieved within the ReadTimeout a IOException will be thrown
try
{
int bytesRead = stream.Read(bytesFrom, 0, bufferSize);
stream.Flush();
if (bytesRead == 0)
{
throw new System.IO.IOException("Connection seems to be refused or closed.");
}
}
catch (System.IO.IOException)
{
byte[] ping = System.Text.Encoding.UTF8.GetBytes("%");
stream.WriteTimeout = 1;
stream.Write(ping, 0, ping.Length);
continue;
}
dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$"));
rCount = Convert.ToString(requestCount);
string message = client.Name + " says: " + dataFromClient;
program.Broadcast(message);
}
catch(Exception ex) when (ex is ObjectDisposedException || ex is InvalidOperationException || ex is System.IO.IOException)
{
Debug.WriteLine(ex.ToString());
program.UserDisconnected(client);
break;
}
catch(ArgumentOutOfRangeException ex)
{
Debug.WriteLine(ex.ToString());
}
catch(Exception ex)
{
Debug.WriteLine(ex.ToString());
break;
}
}
}
Bedeutet dies, dass Sie nicht feststellen können, ob der Client gegangen ist? Beim Betrachten der Doku sollte es eine ObjectDispoedException oder zumindest eine IOException auslösen, weil es nicht mehr davon lesen kann. – chris579
Ein _graceful_ disconnect ist kein Ausnahmefall und wird von 'stream.Read()' gefunden, das 0 zurückgibt habe einen Exception-Handler, aber ich bezweifle, dass "ObjectDisposedException" ausgelöst wird, es sei denn, du entwirfst es selbst und versuchst es dann zu benutzen. –
Sie haben Recht, DisposedException wird nur ausgelöst, wenn dieses Objekt noch vorhanden ist und nicht vom Garbage Collector gelöscht oder manuell entfernt wurde. Aber, großer Dank, das hat funktioniert! Ich werde Ihre Antwort so schnell wie möglich akzeptieren. Edit: Wenn ich den Client schließe, wird die Schleife nicht beendet und bleibt, bis die Serveranwendung geschlossen wurde. Wie könnte ich das beheben? – chris579