.net 如何在没有异常的情况下优雅地关闭TCP连接?

.net 如何在没有异常的情况下优雅地关闭TCP连接?,.net,tcp,.net,Tcp,模式是什么和/或您将如何更改以下代码,以便可以从服务器或客户端正常关闭连接,而无需异常处理 TcpClient与Socket:我不喜欢使用TcpClient 客户端类。我写了以下内容 用于尝试演示 最简单的情况。我曾经 使用套接字&SocketAsyncEventArgs 但事情变得太糟了 处理这个问题很复杂 阻塞与异步:因为 阻止呼叫这可能很困难 或者不可能。如果是,那很好,但是 你是如何解决这个问题的 异步情况 退出令牌?:我尝试过向另一方发送某种“退出”令牌,这样它就知道要关闭,但还没有成

模式是什么和/或您将如何更改以下代码,以便可以从服务器或客户端正常关闭连接,而无需异常处理

  • TcpClient与Socket:我不喜欢使用TcpClient 客户端类。我写了以下内容 用于尝试演示 最简单的情况。我曾经 使用套接字&SocketAsyncEventArgs 但事情变得太糟了 处理这个问题很复杂

  • 阻塞与异步:因为 阻止呼叫这可能很困难 或者不可能。如果是,那很好,但是 你是如何解决这个问题的 异步情况

  • 退出令牌?:我尝试过向另一方发送某种“退出”令牌,这样它就知道要关闭,但还没有成功,我想在这里给出一个简单的示例

  • 无论如何都需要异常处理:我知道在实际应用程序中,异常处理是必要的,因为网络连接等会失败。但是,是否可以毫无例外地处理预期的正常停机情况

  • 编辑:我将原始代码和应答代码移动到

    原始失败示例:移至此处:

    当前工作答案


    TcpClient实现IDisposable,因此您应该能够像这样使用它,然后不用担心关闭客户端-无论是否引发异常,using语句都应该为您完成这项工作:

    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类型会在文档(例如:)中明确表示它们关闭了其特定的底层资源,但这一问题的解决方案异常安静-您可能需要首先测试这一点。

    在调用Socket.close()之前使用Socket.Shutdown()。等待关机处理完成(例如,ReceiveAsync()将返回0字节)

  • 抽象选择(大部分)不是问题
  • 异步I/O意味着永远不必看到您的错误
  • 来自Socket.ReceiveAsync()方法的MS文档:对于字节流,已读取的零字节表示正常关闭,并且不再读取更多字节

  • 我已经有一段时间没有使用套接字了,但我记得您必须为它们调用shutdown()


    我猜,与.NET等效的是
    socket.Shutdown(SocketShutdown.Both)

    如果一方关闭连接,上面的当前示例将引发异常。使用将不会捕获异常。无论如何,我正在寻找一种方法来避免在正常关闭期间完全抛出异常。
    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();
            }
        }
    }