現在、私は単純なクライアントサーバーチャットプログラム(C#のクライアントサーバー通信の事に入りたい)に取り組んでいます。これは、サーバーから正しく切断されていない場合を除き、これまでのところ動作します。私は、接続を閉じるために、ここで、このコードを使用するクライアントでTcpClientとNetworkStreamを閉じる際の問題
:クライアントからのメッセージを待っているスレッド化ループが存在しているサーバー上
client.Client.Disconnect(false); // client is the TcpClient
client.Close();
:
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;
}
}
クライアントが接続を切断します上記のコードでは、関数は常にストリームをフェッチして、そのような出力を生成しています。
\0\0\0\0\0\0\0 [and so on]
$
のインデックスがないため、この場合はArgumentOutOfRangeException
がスローされます。私はループを避けて無限に実行するためにbreak
を追加しました。
驚いたことに、ObjectDisposedException
は投げられません。また、ストリームが閉じられて接続が拒否されたため、System.IO.IOException
はスローされません。
サーバに接続されているクライアントアプリケーションを閉じるだけでは、サーバはループを停止せず、クライアントが切断されたためにストリームが到着するのを待っています。
クライアントの接続が切断されたかどうかを検出するにはどうしたらいいですか?そして、私は接続を閉じるために適切な方法をクライアント接続を閉じる方法ですか?
ありがとうございました!
更新:
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;
}
}
}
これは、クライアントがなくなったことを検出できないことを意味しますか?ドキュメントを見るとObjectDispoedExceptionまたは少なくともIOExceptionがスローされるはずです – chris579
_graceful_ disconnectは例外ではなく、0を返す 'stream.Read()'によって検出されます。例外ハンドラを持っていますが、自分で処理してから使用しようとしない限り、 'ObjectDisposedException'がスローされることはありません。 –
そうですが、このオブジェクトがまだ存在し、ガベージコレクタによって削除されていないか手動で処理されていない限り、DisposedExceptionはスローされません。しかし、巨大な感謝、これは働いた!私はあなたの答えをできるだけ早く受け入れます。 編集:クライアントを閉じると、ループは終了せず、サーバーアプリケーションが終了するまで保持されます。どうすればこの問題を解決できますか? – chris579