2009-08-26 43 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.Close()之前使用Socket.Shutdown()。等待关闭处理完成(例如ReceiveAsync()将返回0字节)。

  1. 抽象选择(大部分)是一个非问题。
  2. 异步I/O意味着永远不会看到你的遗憾。
  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将明确地说,他们关闭自己的具体基础资源的文档中(例如:SqlConnection)正常CLR类型,但对此事的TcpClientdocs是出奇安静—你可能想先测试一下。

+0

当前示例如果一方关闭连接上述将抛出异常。使用不会陷入异常。无论如何,我正在寻找一种避免在正常关机期间完全抛出异常的方法。 – 2009-08-26 19:07:48

0

我还没有做过一段时间的套接字,但我记得你必须为它们调用shutdown()。

在.NET等效,我想,将socket.Shutdown(SocketShutdown.Both)