1

明確にするために、ここで参照しているすべてのTCPClientは、私自身のクラスのインスタンスではなく、Monoの.NET4.0の実装からのSystem.Net.Sockets.TcpClientのインスタンスです。

サーバーと同じように、クライアント接続をリッスンしているサーバーがあります。新しいクライアントを取得するたびに、新しいスレッドで接続を処理するための新しいTCPClientを作成します。私は辞書ですべての接続とスレッドを追跡しています。クライアントが切断すると、サーバーに切断メッセージが送信され、TCPClientが閉じられ、ディクショナリエントリが削除され、スレッドが自然に停止します。大騒ぎも大騒ぎもありません。サーバーは複数のクライアントを問題なく処理できます。

ただし、クライアントが切断され、切断メッセージを送信してから再接続した場合に何が起こるかをシミュレートしています。クライアントがユーザー名システムに再接続したかどうかを検出しています(テストが完了すると、より安全になります)。新しいTCPClientを作成し、古いTCPClientを実行したままにすると、システムは正常に機能しますが、スペースを占有して何もしない無用なスレッドがたくさんあります。怠け者。

そのため、古い接続に関連付けられているTCPClientを閉じようとします。これを行うと、新しいTCPClientも停止し、クライアントプログラムは次のエラーをスローします。

E/mono    (12944): Unhandled Exception: System.IO.IOException: Write failure ---> System.Net.Sockets.SocketException: The socket has been shut down

そして、サーバーはこのエラーをスローします:

Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.

Cannot read from a closed TextReader.

したがって、次のようなリモートエンドポイントで古いTCPClientを閉じます。192.168.1.10:50001

また、次のようなリモートエンドポイントで新しいTCPClientを中断します。192.168.1.10:50002

したがって、2つのTCPClientオブジェクトのリモートエンドポイントIPアドレスは同じですが、リモートエンドポイントポートは異なります。しかし、一方を閉じると、もう一方が機能しなくなるようです。新しいTCPClientを閉じずに、古いTCPClientを閉じてクリーンアップを実行できるようにしたい。

これは、TCPClientが低レベルのソケットでどのように機能するかと関係があると思いますが、それを実際に理解していないため、修正する立場にありません。

4

3 に答える 3

1

ソケットサーバーでも同様の問題が発生しました。辞書の代わりに単純なリストを使用して、現在のすべての接続を保持しました。新しいストリームをリッスンする連続的なwhileループでは、try / catchがあり、catchブロックでは、クライアントが切断されている場合、クライアントを強制終了します。

sever.csでこのようなもの:

public static void CloseClient(SocketClient whichClient)
        {
            ClientList.Remove(whichClient);
            whichClient.Client.Close();
            // dispose of the client object
            whichClient.Dispose();
            whichClient = null;
        }

次に、クライアントでの単純なdisposeメソッド:

public void Dispose()
        {
            System.GC.SuppressFinalize(this);
        }

編集:この貼り付けは、私のコードの助けを借りて彼または彼女が自分で見つけたOPの解決策です。

したがって、明確にするために、状況は、異なるリモートエンドポイントポートを持つ2つのTCPClientオブジェクトTCPClientAとTCPClientBがありますが、IPは同じです。

TCPClientA.Client.RemoteEndPoint.ToString();

戻り値:192.168.1.10:50001

TCPClientB.Client.RemoteEndPoint.ToString();

戻り値:192.168.1.10:50002

TCPClientAは役に立たなくなったため、クリーンアップする必要があるので、

TCPClientA.Close();

ただし、これにより、何らかの理由でTCPClientBのもう一方の端にあるクライアントのソケットが閉じられます。しかし、書く

TCPClientA.Client.Close();
TCPClientA.Close();

TCPClientBに干渉することなく、TCPClientAを正常に閉じます。だから私は問題を修正しましたが、なぜそれがそのように機能するのか理解できません。

于 2012-02-08T01:58:20.757 に答える
-2

これは明らかにコードのエラーです。1つのインバウンド接続を閉じるだけでは、別の接続を閉じることはできません。明らかに、コードの他の場所で何か他のことが起こっています。

于 2012-02-08T09:27:17.463 に答える
-2

解決策を見つけたように見えますが、.netでクライアント/サーバーアプリケーションを作成するときに同様の落とし穴がたくさんあることを知っています。これらの問題がすでに解決されているオープンソースのネットワークライブラリ(monoで完全にサポートされています)、networkComms.netがあります。基本的なサンプルはこちらです。

免責事項:これは商用製品であり、私は創設者です。

于 2012-02-10T12:30:52.220 に答える