Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET中查找下一个TCP端口的线程安全方式(通过多个进程)_C#_Multithreading_Networking_Tcp_Concurrency - Fatal编程技术网

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

C# 在.NET中查找下一个TCP端口的线程安全方式(通过多个进程),c#,multithreading,networking,tcp,concurrency,C#,Multithreading,Networking,Tcp,Concurrency,请注意,您可以在此处找到类似的问题: 我的问题是这个问题的解决方案(公认的答案)不是线程安全的: 我写了一个测试来证明: private readonly BlockingCollection<int> _freePorts = new BlockingCollection<int>(); [Test] public void FreeTcpPort_ShouldBeThreadSafe() { // Act Parallel.For(0, 10000,

请注意,您可以在此处找到类似的问题:

我的问题是这个问题的解决方案(公认的答案)不是线程安全的:

我写了一个测试来证明:

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());
}
问题是在这种情况下,端口51475返回两次。请注意,相同的端口是从2个并行运行的线程返回的,而不是因为它在端口范围内循环并获得重叠(循环计数较高时会发生重叠)

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

我如何构建一个实用程序,从并行运行的进程中获得一个免费的TCP端口,而不陷入竞争状态?

我如何构建一个实用程序,从并行运行的进程中获得一个免费的TCP端口,而不陷入竞争状态

你不能。使用一些临时“空闲”端口的想法从一开始就是错误的,因为在一个有多个进程的系统上,实际空闲的端口可以随时更改,无论应用程序本身是否使用线程。因此,即使您找到了一些现在可用的端口,在您成功绑定到它之前,它也可能已被另一个进程使用


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

除非这是某种编码实践,我建议您:a)让操作系统选择它的端口,b)解析
netstat-a-n-ptcp
输出以获取使用过的端口(如果a不可能)。如公认的答案所示,正确的方法是让操作系统使用端口0选择端口。在多进程系统上,无论您是否使用线程,其他一切都容易出现争用情况。即使您发现了一个看似未使用的端口(使用bradbury9建议的netstat),绑定也可能会失败,因为另一个进程也发现了这个端口,并在您的进程能够完成之前绑定到它。好的,您可以立即
Stop()
侦听器,使该端口再次可用,为什么操作系统应该避免再次使用该端口?@SteffenUllrich OP在问题的第一句话中提到了“类似的问题”。他还包括了这个问题的公认答案,并解释了为什么这个答案不适合他的需要(他声称它不是线程安全的)。除非您主动绑定到打开的端口并使用它,否则除了应用程序线程之外的任何其他进程都可能使用它,并且您无法阻止它。您不应该使用
static int freetcport()
,而应该使用
static TcpListener Connect()
,只需读取打开的端口号即可。否则机器中的其他进程可能会打开它,您无法阻止进程外的竞争条件。谢谢您的回答。对我来说有道理。我知道在停止侦听器后,另一个进程可能会使用此端口。因为我们只在测试代码中使用这个实用程序,所以如果操作系统能够以安全的方式循环(增加)端口,它就已经足够好了。我仍然不明白为什么情况并非总是如此。(在我们的测试环境中没有其他进程可以窃取空闲端口),但我们必须找到一个解决方案,在将WCF服务绑定到端口0后确定使用了哪个动态端口,就像你建议的那样。@JonasBenz:操作系统没有必要按照你希望的方式处理端口,但实际上会付出更多的努力(没有明显的收益)。这一需求仅在您这一部分,而且仅仅是因为您的测试是建立在关于操作系统行为的假设之上的,而这些假设是不真实的。不要期望操作系统与你的假设保持一致,而是让你的假设与操作系统的行为保持一致。你完全正确。我们可以按照你建议的方式解决我们的问题。
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());
}
51470
51472
51473
51365
51475
51367
51366
51474
51475
51476
51478
51479
51480