1

小さな IRC サーバーを作成して、いくつかの新しいプログラミングの概念 (および私がずっと使用していない他の概念) を学習する実験を行っています。最初のステップは、TCP 経由で接続する基本的なクライアントを取得して、プレーンテキスト コマンドをサーバーに送信することです。

接続をリッスンするには、次のコードがあります。

public NetworkClient(Server server, TcpClient socket, int id)
{
    _socket = socket;
    _id = id;
    _server = server;
}

private async void ListenForClients()
{
    int numClients = 0;
    while (IsRunning)
    {
        var tcpClient = await _listener.AcceptTcpClientAsync();
        var netClient = new NetworkClient(this, tcpClient, numClients);
        netClient.Start();
        Console.WriteLine("Client Connected");

        numClients++;
    }
}

次に、私のNetworkClientクラスでは、私のStart()メソッドは次のようになります。

public async void Start()
{
    using (var reader = new StreamReader(_socket.GetStream()))
    {
        while (_server.IsRunning)
        {
            var line = await reader.ReadLineAsync();
            Console.WriteLine("Client {0} wrote: {1}", _id, line);
        }
    }
}

これは、Telnet クライアントが接続されている間はうまく機能しますが、いったん Telnet クライアントを閉じると、reader.ReadLineAsync();常にnull. チェックを追加して確認しline == nullますが、クライアントが切断されたかどうかを検出する正しい方法かどうかはわかりません。

さらに悪いことに、_socket.Connectednull が によって「受信」されている間、常に true を返していますreader.ReadLineAsync()

TCP クライアントが切断されたことを検出する適切な方法は何ですか?

4

1 に答える 1

6

接続が正常に閉じられた場合、TCP/IP ソケットを読み取ると 0 バイトが返されます。この状況によりReadLineAsync、 が返されnullます。したがって、はい、それを確認しnullて、適切なソケット閉鎖として扱う必要があります。

ソケットは他の方法でも閉じることができます。ソケットが強制的に閉じられた場合、ソケット操作は例外をスローする可能性があります。プロトコルの許容可能な部分 (クローズがエラーと見なされない) で例外が発生した場合は、その例外も適切なクロージャーであるかのように扱う必要があります。

ああ、そしてTcpClient.Connected(like Socket.Connected) は実質的に役に立ちません。ソケットが接続されているかどうかではなく、ソケット接続されているかどうかのみを示します。そのプロパティが存在しないふりをしてください。

最後に、いくつかの注意事項:

  • 避けてくださいasync void。メソッドが を返す場合、メソッドTaskがいつ完了するか (および例外が発生したかどうか) を確認するための「ハンドル」があります。私の最近の MSDN 記事では、推奨されない理由async voidが説明されています。
  • 接続を介して定期的にデータを送信し、データがまだ実行可能かどうかを判断することをお勧めします。これについて詳しく説明したTCP/IP .NET ソケット FAQを書きました。
于 2013-04-22T02:09:15.293 に答える