首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何毫无例外地优雅地关闭TCP连接?

如何毫无例外地优雅地关闭TCP连接?
EN

Stack Overflow用户
提问于 2009-08-26 18:43:50
回答 3查看 4.5K关注 0票数 1

模式是什么和/或如何更改以下代码,以便可以从服务器或客户端优雅地关闭连接,而不需要异常处理。

  1. TcpClient vs.套接字:,我不想使用TcpClient客户端类。我编写了以下代码,试图演示最简单的情况。我一直在使用套接字& SocketAsyncEventArgs,但是处理这个问题变得太复杂了。
  2. 阻塞与异步:由于阻塞调用,这可能是困难的或不可能的。如果是这样的话,那很好,但是在异步情况下如何解决呢?
  3. 退出令牌?:--我已经尝试过将某种“退出”令牌发送到另一边,以便它知道要关闭,但是它没有工作,我想在这里给出一个最小的示例。
  4. 异常处理需要任何方式:我知道,在实际应用程序中,异常处理将是必要的,因为网络连接等将失败。但是,期望的情况是否可以毫无例外地处理呢?

编辑:,我将原始代码和应答代码移到了要旨

原始失败示例:迁移到这里:original.cs

当前工作答案:answer.cs

代码语言:javascript
复制
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);
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-08-26 19:16:25

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

  1. 抽象的选择(大部分)不是一个问题。
  2. 异步I/O意味着永远不需要看到你的遗憾。
  3. 对于Socket.ReceiveAsync()方法的MS文档:对于字节流,已经读取的零字节表示优雅的闭包,并且再也不会读取更多的字节。
票数 2
EN

Stack Overflow用户

发布于 2009-08-26 19:04:50

TcpClient实现了IDisposable,所以您应该能够像这样使用它,然后就不用担心关闭客户机了-- using语句应该为您做这件事,不管是否抛出异常:

代码语言:javascript
复制
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),但在这个问题上的TcpClient 文档却异常安静--您可能需要先测试一下。

票数 0
EN

Stack Overflow用户

发布于 2009-08-26 19:18:40

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

我想,.NET的等价物应该是socket.Shutdown(SocketShutdown.Both)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1336709

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档