c# - 在 .NET 中查找下一个 TCP 端口的线程安全方式(通过多个进程)

标签 c# multithreading networking tcp concurrency

请注意,您可以在此处找到类似的问题:Find the next TCP port in .NET

我的问题是这个问题的解决方案(接受的答案)不是线程安全的:Find the next TCP port in .NET - Top answer

static int FreeTcpPort()
{
    TcpListener l = new TcpListener(IPAddress.Loopback, 0);
    l.Start();
    int port = ((IPEndPoint)l.LocalEndpoint).Port;
    l.Stop();
    return port;
}

我写了一个测试证明:

private readonly BlockingCollection<int> _freePorts = new BlockingCollection<int>();

[Test]
public void FreeTcpPort_ShouldBeThreadSafe()
{
    // Act
    Parallel.For(0, 10000,
        index =>
        {
            int freeTcpPort = FreeTcpPort();
            _freePorts.Add(freeTcpPort);
            Console.WriteLine(freeTcpPort);
        } );

    var query = _freePorts.GroupBy(x => x)
        .Where(g => g.Count() > 1)
        .Select(y => new { Element = y.Key, Counter = y.Count() })
        .ToList();

    // Assert
    Assert.That(query.All(x => x.Counter == 1), () => query.First(x => x.Counter > 1).ToString());
}

上面的测试是不稳定的。在我的机器上,它失败的次数超过 50%。 这是失败测试的控制台输出的一部分:

51470
51472
51473
51365
51475
51367
51366
51474
51475
51476
51478
51479
51480

问题是在这种情况下端口 51475 被返回了两次。请注意,同一端口是从 2 个并行运行的线程返回的,而不是因为它在端口范围内循环并重叠(发生在较高的循环计数时)。

请注意,仅仅为我的用例添加一个锁定语句是不够的,因为我将此动态端口用于并行运行的系统测试,这些测试在单独的进程中运行。 因此,我正在寻找一种解决方案,它总是为并行运行的进程返回一个唯一且免费的 TCP 端口。

我如何构建一个实用程序来从并行运行的进程中获取空闲的 TCP 端口,而不会遇到竞争条件?

最佳答案

How can I build a utility to get a free TCP port from parallel running processes, without running into race conditions?

你不能。使用一些临时“空闲”端口的想法从一开始就是错误的,因为在具有多个进程的系统上,实际上空闲的东西可能会从一个时刻变为另一个时刻 - 无论您的应用程序本身是否使用线程。因此,即使您找到了一些现在空闲的端口,它也可能在您设法绑定(bind)到它之前已被另一个进程使用。

正确的方法是不要找到空闲端口然后绑定(bind)到它。正确的方法是将您的监听器绑定(bind)到端口 0,然后确定实际使用了哪个端口。然后直接使用这个已经创建的监听器套接字,而不是关闭它并尝试使用它用于某些新套接字的端口。

关于c# - 在 .NET 中查找下一个 TCP 端口的线程安全方式(通过多个进程),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58063770/

相关文章:

c# - 更新实体

c# - ef核心脚手架外键冲突

java - Android camera : Threads? 哪个应该做什么

networking - Vagrant 盒子创建后 - 断开网络电缆

networking - 我可以在 SRV 记录中使用 IP 地址吗?

c# - 如何在没有邮箱的情况下使用具有 Windows 身份验证和身份的 EWS 发送和保存电子邮件?

C# 2 ComboBox DropDownList 显示相同的值

C++线程数据库类内存混合

java - JVM——堆和栈

linux - 基于虚拟盒的嵌入式 Linux 开发