2009-08-26 15 views
1

例外ハンドリングを必要とせずに、サーバまたはクライアントから正常に接続を閉じることができるように、パターンやパターンを教えてください。ソケット対TCP接続を例外なく正常に閉じるにはどうすればよいですか?

  1. れるtcpClient:は私がれるtcpClient クライアントクラスを使用することに縛られていませんよ。私は次のような コードを書いて、 の可能な最も単純なケースを実証しようとしています。私は ソケットを使用していた& SocketAsyncEventArgs しかし、この問題に対処するには も複雑になっていました。非同期対ブロッキング

  2. :ので ブロッキング呼び出しのこれは 困難または不可能かもしれません。もしそうなら、それはいいですが、 非同期のケースではどうやって解決しますか?

  3. トークン?:私は「終了」それはシャットダウンに知っているように、他の側にトークンのいくつかの種類を送信して実験してきたが、それは働いてもらっていないを終了し、私はここで、最小限の例を提示したかったです。

  4. とにかく必要な例外処理:私は、ネットワーク接続などが失敗すると例外処理が実際のアプリケーションに必要になります知っています。しかし、は予期しないシャットダウンのケースが例外なく処理されることはできませんか?

編集:私は、元の移動とgistにコードを答えます。

オリジナルは不合格:ここに移動:https://gist.github.com/958955#file_original.cs

現在の作業回答:https://gist.github.com/958955#file_answer.cs

class Channel 
{ 
    private readonly TcpClient client; 
    private readonly NetworkStream stream; 
    private readonly string name; 
    private readonly ManualResetEvent quit = new ManualResetEvent(false); 

    public Channel(string name, TcpClient client) 
    { 
     this.name = name; 
     this.client = client; 
     stream = client.GetStream(); 
    } 

    public void Run() 
    { 
     Console.WriteLine(name + ": connected"); 
     byte[] buffer = new byte[client.Client.ReceiveBufferSize]; 
     stream.BeginRead(buffer, 0, buffer.Length, this.Read, buffer); 

     var writer = new StreamWriter(stream, Encoding.ASCII); 

     while (true) 
     { 
      var line = Console.ReadLine(); 
      if (String.IsNullOrEmpty(line) || !this.client.Connected) break; 

      writer.WriteLine(line); 
      writer.Flush(); 
     } 

     if (client.Connected) 
     { 
      Console.WriteLine(name + " shutting down send."); 
      client.Client.Shutdown(SocketShutdown.Send); 
      Console.WriteLine(name + " waiting for read to quit."); 
      quit.WaitOne(); 
     } 
     else 
     { 
      Console.WriteLine(name + " socket already closed"); 
     } 

     Console.WriteLine(name + " quit, press key to exit."); 
     Console.ReadKey(); 
    } 

    private void Read(IAsyncResult result) 
    { 
     var bytesRead = this.stream.EndRead(result); 
     if (bytesRead == 0) 
     { 
      Console.WriteLine(name + " read stopped, closing socket."); 
      this.client.Close(); 
      this.quit.Set(); 
      return; 
     } 

     var buffer = (byte[])result.AsyncState; 
     Console.WriteLine(name + " recieved:" + Encoding.ASCII.GetString((byte[])result.AsyncState, 0, bytesRead)); 

     stream.BeginRead(buffer, 0, buffer.Length, this.Read, buffer); 
    } 
} 

答えて

2

Socket.Shutdown()を使用してからSocket.Close()を呼び出します。シャットダウン処理が完了するまで待ちます(ReceiveAsync()は0バイトを返します)。

  1. 抽象化の選択は(ほとんど)非問題です。
  2. 非同期入出力は、あなたのごめんなさいを見たことがないことを意味します。
  3. Socket.ReceiveAsync()メソッドのMSドキュメントから:バイトストリームの場合、読み込まれたゼロバイトは優雅なクロージャを示し、これ以上のバイトは読み取られないことを示します。
0

れるtcpClientがIDisposableインターを実装して、あなたはのようにそれを使用することができるはずですので、クライアントを閉じることについて心配しないでください。使用するステートメントは、例外がスローされません。

class Client 
{ 
    static void Main(string[] args) 
    { 
     using (TcpClient client = new TcpClient(AddressFamily.InterNetwork)) 
     { 

      Console.WriteLine("client: created, press key to connect"); 
      Console.ReadKey(); 

      client.Connect(IPAddress.Loopback, 5000); 

      var channel = new Channel("client", client); 
      channel.Run(); 
     } 
    } 
} 

言った、通常はIDisposableインターを実装するCLR型は、彼らは文書(例:SqlConnection)での特定の基となるリソースを閉じて、明示的に言うだろうが、問題のTcpClientdocsが妙に静かです—これを最初にテストすることができます。

+0

現在の例になります。 usingは例外をトラップしません。それにもかかわらず、私は優雅なシャットダウン中に例外を完全に投げるのを避ける方法を探しています。 –

0

私はしばらくソケットを行っていませんが、シャットダウン()を呼び出さなければならないことを覚えています。

.NETの同等は、私が推測する、片側が接続を閉じた場合、例外がスローされます上記socket.Shutdown(SocketShutdown.Both)

関連する問題