【问题标题】:Async TcpClient Connect different when deployed on Windows and LinuxAsync TcpClient Connect 在 Windows 和 Linux 上部署时不同
【发布时间】:2018-12-05 21:31:34
【问题描述】:

我正在编写一个客户端应用程序,它必须通过 TCP 套接字连接到服务器应用程序。选择的框架是 .NET Core 2.0(它不是 ASP.NET Core,它只是一个控制台应用程序)。我正在使用TcpClient 类及其.BeginConnect().EndConnect() 方法,以便能够设置连接超时。代码如下:

public class Program
{
    public static void Main(String[] args)
    {
        var c = new TcpClient();
        int retryCount = 0;
        var success = false;
        IAsyncResult res;
        do
        {
            if (retryCount > 0) Console.WriteLine("Retry: {0}", retryCount);
            retryCount++;
            c.Close();
            c = new TcpClient();
            res = c.BeginConnect("10.64.4.49", 13000, null, null);
            success = res.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2));
            Console.WriteLine(success.ToString());
        }
        while (!c.Connected);

        c.EndConnect(res);
        Console.WriteLine("Connected");
        Console.ReadLine();

    }

当我编译、发布和运行这个控制台应用程序时,没有任何东西在监听 IP 地址和端口,如果应用程序在 Windows 或 Linux 上运行,结果会有所不同。 以下是 Windows 上的结果:

这是它在 Linux 上的样子:

结果几乎相同,唯一的区别是在 Windows 上它每两秒尝试连接一次,但在 Linux 上,它的行为就像这两秒被忽略并继续进行我所说的“狂暴连接会话”。 我不确定这是 Windows 已经预定义的 .NET Core 问题还是某些 Linux 调整。 任何人都可以建议可能是什么问题,并最终提出解决方案。

提前致谢,

朱利安·迪米特洛夫

【问题讨论】:

  • 您是否进行了测试以检查您对 WaitOne 和 TimeSpan 的假设?
  • WaitOneTimeSpan 作为超时值,而不是等待时间。您正在等待异步任务(连接)完成。您的连接是成功的,所以它会在连接建立后立即完成。
  • WaitOne()' called on a ManualResetEvent on both Win and Linux act the same. Before I use TimeSpan` 我刚刚输入 2000 的毫秒数 - 在两个操作系统上的结果相同
  • @Julian BeginConnect 返回一个 IAsyncResultManualResetEvent.WaitOne 的文档表明这是一个延迟,而 WaitHandle.WaitOne 表明这是一个超时。
  • 应用结构的灵感来自this问题的答案。我找不到在 IAsyncResult 上与 .BeginConnect 方法分开测试 WaitHandle.WaitOne 的方法。我仍然找不到合理的答案,为什么它适用于 Windows 而不是 Linux...

标签: c# linux windows asp.net-core .net-core


【解决方案1】:

我想我理解您遇到问题的原因,这似乎是基于对超时应该做什么的误解。

为了测试,我把你的代码改成这样:

var sw = Stopwatch.StartNew();
res = c.BeginConnect("127.0.0.1", 12, null, null);
success = res.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(10));
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

在 Windows 上,我可以看到大约 1 秒后连接失败,而在 Linux 中运行相同的代码,它几乎立即失败。似乎 Linux 能够确定连接是否比 Windows 更快。我想你可能弄错了 Windows 计算出它无法连接到你指定的超时时间。

下一步:什么是超时?超时是最大时间可以建立一个连接。这是一个限制。这意味着操作必须在不到 X 秒(例如 10 秒)内完成,否则会失败。如果一个操作在 1 秒内完成,则立即返回。

【讨论】:

  • 我发现的另一个有趣的事情是,当您从示例中删除 success = res.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(10)); 行时......它在 Windows 和 Linux 上的作用相同 :)
  • 那是因为,通过移除等待,您是在异步尝试连接,而不是等待找出结果。
  • 因此,无论您在.AsyncWaitHandle.WaitOne() 中输入什么内容,Windows 上总是会在大约 1 秒后尝试重新连接,但在 Linux 上几乎是立即
  • 朱利安,这是因为您只定义了它可以花费的最长时间 - 这不是延迟。如果要插入延迟,则需要在失败时使用 Thread.Sleep 之类的东西。
  • 是的,我明白了这个问题,感谢您的解释,行动将是把Thread.Sleep() 插入延迟。感谢您的回答!
猜你喜欢
  • 1970-01-01
  • 2021-02-23
  • 2012-01-17
  • 1970-01-01
  • 2015-03-02
  • 1970-01-01
  • 2014-04-10
  • 2011-08-09
  • 2018-07-06
相关资源
最近更新 更多