トップ回答者
TcpClientの切断で異常になる

質問
-
お世話になっております。
表題の通り、TcpClientで接続後、切断処理を行うとおかしくなります。
症状を以下に示します。クライアント側接続:
_connect.Reset(); client = new TcpClient(); client.BeginConnect(ip, port, new AsyncCallback(ConnectCallback), client);
サーバ側受信処理:
private void ProcessMessage(StreamReader reader) { lock (this) { string message = reader.ReadLine(); switch (message) { } } }
クライアントから、接続後、conectedプロパティはtrueとなり、正常にメッセージの
送受信が完了します。ところが、
client.Close();
後、何もメッセージを送信していないのに、サーバ受信側でnullが受信され”続けます”。
且つ、その後のTcpClientオブジェクトは以下のようになります。
何が起こっているのでしょうか?
切断方法がおかしいのでしょうか?
識者の方、ご教示ください。
回答
-
末尾というか、【切断を完了した後もずっとnullを受信し続ける】動作が正常ということでしょうか?
StreamReaderにとって入力ストリームが何であるかは関係ありません。ですからネットワーク切断に限らず、FileStreamでも入力ストリームの末尾に到達した場合は同じことになります。そこには「受信し続ける」という意味はなくStreamReaderは仕様に従ってnullを返しただけです。
今回、ご質問させて頂きましたのは、ほかに問題がありまして
質問文にしか答えることができません。質問したい内容を書きましょう。
その後、同じロジックを用いて、再接続するのですが
接続完了後(conectedプロパティがtrue後)に、メッセージを送信してもnullを受信し続け
本来の送りたいメッセージが受け取れていないという問題です。その原因は、nullを受信し続けることにあって、その為に正常に受信できていないと
思っていますが、また別の問題があるのでしょうか。- 回答としてマーク コーベル 2015年8月19日 5:30
すべての返信
-
client.Close();
後、何もメッセージを送信していないのに、サーバ受信側でnullが受信され”続けます”。入力ストリームの末尾に到達した場合は null。
と書かれているので、ドキュメント通りの動作ではありませんか?
-
佐祐理さん、ご回答ありがとうございます。
末尾というか、【切断を完了した後もずっとnullを受信し続ける】動作が正常ということでしょうか?
今回、ご質問させて頂きましたのは、ほかに問題がありまして
その後、同じロジックを用いて、再接続するのですが
接続完了後(conectedプロパティがtrue後)に、メッセージを送信してもnullを受信し続け
本来の送りたいメッセージが受け取れていないという問題です。その原因は、nullを受信し続けることにあって、その為に正常に受信できていないと
思っていますが、また別の問題があるのでしょうか。というか、closeしたインスタンス以外の、どのインスタンスが送り続けているのでしょうか。
すみません、説明足らずですよね。
-
末尾というか、【切断を完了した後もずっとnullを受信し続ける】動作が正常ということでしょうか?
StreamReaderにとって入力ストリームが何であるかは関係ありません。ですからネットワーク切断に限らず、FileStreamでも入力ストリームの末尾に到達した場合は同じことになります。そこには「受信し続ける」という意味はなくStreamReaderは仕様に従ってnullを返しただけです。
今回、ご質問させて頂きましたのは、ほかに問題がありまして
質問文にしか答えることができません。質問したい内容を書きましょう。
その後、同じロジックを用いて、再接続するのですが
接続完了後(conectedプロパティがtrue後)に、メッセージを送信してもnullを受信し続け
本来の送りたいメッセージが受け取れていないという問題です。その原因は、nullを受信し続けることにあって、その為に正常に受信できていないと
思っていますが、また別の問題があるのでしょうか。- 回答としてマーク コーベル 2015年8月19日 5:30
-
佐祐理さん、ご回答ありがとうございます。
>入力ストリームの末尾に到達した場合は同じことになります。そこには「受信し続ける」という意味はなくStreamReaderは仕様に従ってnullを返しただけです。
なるほど、仕様として理解するのみですね。
Close()しなければ起こらないので、どういう処理が一番適しているのか知りたかった
次第です。>その新しいTcpClientインスタンスをどう処理したのでしょうか?
リスナーは、initialで設定する以外の処理はしておりません。
private void ServerStart() { try { listener = new TcpListener(IPAddress.Any, port); listener.Start(); threadServer = new Thread(new ThreadStart(ServerListen)); threadServer.Start(); } catch (Exception exception) { } } ********************************* private void ServerListen() { try { TcpClient server = listener.AcceptTcpClient(); NetworkStream ns = server.GetStream(); serverReader = new StreamReader(ns, Encoding.UTF8); serverWriter = new StreamWriter(ns, Encoding.UTF8); while (true) { ProcessMessage(serverReader); } } catch (Exception exception) { } } ********************************* private void ProcessMessage(StreamReader reader) { lock (this) { string message = reader.ReadLine(); switch (message) { } } }
ServerStart()は最初にコールされ、その後はCloseイベントで破棄するだけとなっています。
>その場合、TcpListener(このクラスを使っているのかもわかりませんが)からAcceptメソッドで新しいTcpClientインスタンスを得ているはず
これは、再接続されるたび(切断後?)に毎回あたらしいインスタンスを使用するということですか?
無知ですみません。
-
また、接続側は、以下の処理を繰り返し実行しているのみとなります。
TcpClient client = new TcpClient("192.168.1.150", port); NetworkStream ns = client.GetStream(); clientReader = new StreamReader(ns, Encoding.UTF8); clientWriter = new StreamWriter(ns, Encoding.UTF8); threadClient = new Thread(new ThreadStart(this.ClientListen)); threadClient.Start(); clientWriter.WriteLine("GetData"); clientWriter.Flush();
1度目は成功するのですが、2度目のメッセージが届きません。