0

サーバーでTCP接続を許可し、送信されている改行で区切られたメッセージをエコーアウトしようとしています。同じサーバーソケットを維持しながら、複数のクライアントが次々に接続できるようにしたい。これが私のコードです:

TcpClient client;

while (true) {
    Console.Write("Waiting for connection... ");
    client = listener.AcceptTcpListener();
    nStream = client.GetStream();
    sReader = new StreamReader(nStream);
    Console.WriteLine("Connected!");

    while (client.Connected) {
        string line = sReader.ReadLine();
        Console.WriteLine(line);
    }
    Console.WriteLine("#Client Disconnected")
}

残念ながら、リモートクライアントが切断されると、「while(client.Connected)」ループから逃れることはありません。代わりに、STDOUTへの無限の書き込みを取得します。

4

1 に答える 1

3

基本的に、TcpClient.Connectionを使用しているプロパティは、思ったとおりに機能しません。MSDNドキュメントから:

http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.connected.aspx

Connectedプロパティは最新の操作の時点での接続の状態のみを反映するため、現在の状態を判別するためにメッセージの送受信を試みる必要があります。メッセージの送信が失敗すると、このプロパティはtrueを返しなくなります。この動作は仕様によるものであることに注意してください。テストから送受信までの間に接続が失われた可能性があるため、接続の状態を確実にテストすることはできません。

要点は、ホストが切断された後、サーバーがストリームから別の行を読み取るのを待機するのをブロックする前に、プロパティTcpClient.Connectionが更新されなかったことです。ブロックする前に、接続がアクティブかどうかを検出するためのより信頼性の高い方法が必要です。

結局のところ、この質問は以前に尋ねられたことがあります。そこで、ここから答えを借りて、OPで使用している形式に適合させました。

https://stackoverflow.com/a/8631090

    static void Main(string[] args)
    {
        TcpClient client = new TcpClient();
        TcpListener listener = new TcpListener(IPAddress.Loopback, 60123);
        listener.Start();

        while (true)
        {
            Console.WriteLine("Waiting for connection...");
            client = listener.AcceptTcpClient();
            Console.WriteLine("Connection found");
            StreamReader reader = new StreamReader(client.GetStream());

            string line = string.Empty;
            while (TestConnection(client))
            {
                line = reader.ReadLine();
                Console.WriteLine(line);
            }
            Console.WriteLine("Disconnected");
        }
    }

    private static bool TestConnection(TcpClient client)
    {
        bool sConnected = true;

        if (client.Client.Poll(0, SelectMode.SelectRead))
        {
            if (!client.Connected) sConnected = false;
            else
            {
                byte[] b = new byte[1];
                try
                {
                    if (client.Client.Receive(b, SocketFlags.Peek) == 0)
                    {
                        // Client disconnected
                        sConnected = false;
                    }
                }
                catch { sConnected = false; }
            }
        }
        return sConnected;
    }

これは私がテストしたときに機能します。機能する理由は、接続を読み書きしようとするまで、接続が閉じているかどうかがわからないためです。これを行うには、盲目的に読み取り/書き込みを試みてから、ソケットが閉じられたときに発生するIO例外を処理します。または、このテスターメソッドが実行していることを実行して、接続が閉じられているかどうかを確認します。

これがお役に立てば幸いです

編集

これが接続が閉じているかどうかを確認する最も効率的な方法である場合とそうでない場合があることに注意してください。ただし、TcpClientに依存するのではなく、読み取り/書き込みによってサーバー側で接続を自分で確認する必要があることを示しています。繋がり。

編集2

私のサンプルは古いリソースをうまくクリーンアップしていません。OCD反応を起こした人にはお詫びします。

于 2012-12-09T04:23:34.820 に答える