TcpClient 套接字 - 每个套接字地址异常的唯一用法

TcpClient socket - only one usage of each socket address exception

在使用 TcpClient 和 TcpListener 时抛出这个异常,我有点不知所措。它第一次工作,然后我再次 运行 它,我得到以下异常:

每个套接字地址 (protocol/network address/port) 通常只允许使用一次 127.0.0.1:8086

我已检查以确保关闭所有打开的连接。我已经尝试在 TcpClient 上手动调用 close 以及使用 IDisposable using 模式,但仍然有同样的问题。

这是代码,如果您将其复制粘贴到 Visual Studio 中,它应该只是 运行(前提是您添加了以下 using 语句)

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

internal class Program
{
    private static void tcpClientConnection()
    {
        Console.WriteLine("Ready");
        Console.ReadKey();

        IPAddress address = IPAddress.Parse("127.0.0.1");

        using (TcpClient client = new TcpClient(new IPEndPoint(address, 8087)))
        {
            client.Connect(new IPEndPoint(address, 8086));

            using (NetworkStream ns = client.GetStream())
            {
                ns.Write(System.Text.Encoding.ASCII.GetBytes("Hello"), 0, "Hello".Length);
                ns.Flush();
            }

            Console.WriteLine("Closing client");
        }
    }

    internal static void Main(string[] args)
    {
        IPAddress address = IPAddress.Parse("127.0.0.1");

        TcpListener server = new TcpListener(new IPEndPoint(address, 8086));
        server.Start();

        using (Task task2 = new Task(tcpClientConnection))
        {
            task2.Start();

            using (TcpClient client = server.AcceptTcpClient())
            {
                using (NetworkStream ns = client.GetStream())
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        ns.CopyTo(ms);
                        byte[] data = ms.ToArray();

                        Console.WriteLine(System.Text.Encoding.ASCII.GetString(data));
                    }
                }
            }

            Console.WriteLine("Server stop");
            Console.ReadKey();

            server.Stop();
        }

        Console.WriteLine("END");
        Console.ReadKey();

    }
}

请注意,我查看了类似问题中提供的解决方案,但未能看出问题所在...

对于 TcpClient,请不要指定本地端点。我认为这解决了问题,无论如何你都不应该这样做,因为它什么也做不了。 指定传出连接的本地端点使 OS select 适当且可用的值。通常,99.9% 的程序都在这样做。

有些程序需要指定本地端点才能仅侦听某些 IP 或接口。看来你不需要那个。

If all the connections are being closed, should it not be ok to continue using the same address and port?

TCP 有一些不直观的行为会导致连接在关闭后停留一段时间。通过让 OS select 你一个新的端口,问题得到缓解。

您可能还想查看 Task 的用法并获得一些最佳实践:使用 Task.Run 并且不要处置。没意义。

我发现一些设置似乎可以大大减少(但不能完全消除)在重复使用指定了本地端点的套接字时出现此错误:

tcpClient.Client.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true );
tcpClient.LingerState = new LingerOption( true, 0 );

我可能还应该提到,在关闭 tcpClient 之前,我将关闭客户端的流并执行以下操作:

if ( tcpClient.Client.Connected )
    tcpClient.Client.Shutdown( SocketShutdown.Both );

这可能会有所帮助,但如果有人想出可以完全防止出现此错误的方法,请分享。