【问题标题】:TcpClient socket - only one usage of each socket address exceptionTcpClient socket - 每个socket地址异常只使用一次
【发布时间】:2015-12-06 14:44:21
【问题描述】:

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

每个套接字地址(协议/网络地址/端口)通常只允许使用一次 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,不要指定本地端点。我认为这可以解决问题,无论如何你都不应该这样做,因为它什么也没做。
  • 好地方,确实马上解决了问题,谢谢!我将阅读指定本地端点的作用。它不是每次都有使用相同端口的套​​接字吗?如果所有的连接都被关闭了,继续使用相同的地址和端口应该不行吗?只是想知道,谢谢

标签: c# .net sockets tcpclient


【解决方案1】:

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

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

如果所有的连接都被关闭了,是不是应该继续使用相同的地址和端口?

TCP 有一些不直观的行为,会导致连接在关闭后停留一段时间。通过让操作系统为您选择一个新端口,该问题得到缓解。

您可能还想了解Task 的使用情况并了解一些最佳做法:使用Task.Run 并且不要丢弃。没意义。

【讨论】:

  • 谢谢,我会尽快接受。最后一个问题,如果你不介意,你知道我们有什么方法可以在连接关闭后强制连接消失吗? :)
  • 在 4.0 上使用 Task.Factory.StartNew。我不熟悉 TCP 连接挥之不去的问题。在任何情况下,您都应该在关闭连接之前调用双方的 Shutdown(Both)。但我认为这并不能解决挥之不去的问题。我认为你根本不需要解决它,通常没有人需要解决它。这是一个罕见的问题。
  • 有些情况需要指定本地端点。
  • @uncaged 我并不是要反驳你。我添加了一个澄清声明。
【解决方案2】:

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

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

我可能还应该提到,在关闭 tcpClient 之前,我正在关闭客户端的流并做:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-28
    • 2011-01-02
    • 1970-01-01
    • 2023-03-31
    相关资源
    最近更新 更多