【问题标题】:Socket receive timeout throws a delayed exception套接字接收超时引发延迟异常
【发布时间】:2014-06-05 17:35:37
【问题描述】:

在 c# 中,我有一个非常简单的服务器/客户端。客户端在接收时设置为超时 500 毫秒。当它超时时,我希望它会抛出一个异常,但是,我会在 500 毫秒后捕获它,总共达到一秒。为了仔细检查我是否只有一台慢速机器,我测试了抛出异常需要多长时间,它是正确的。这里有一些sn-ps。

服务器线程:

void ServerThreadProc()
{
    using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
    {
        server.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345));
        server.Listen(10);
        using (Socket accepted = server.Accept())
        {
            // Wait so long that client times out.
            System.Threading.Thread.Sleep(5000);
            accepted.Shutdown(SocketShutdown.Both);
            accepted.Close();
        }
    }
}

测试接收超时(失败):

public void ShouldNotExceedConnectionTime()
{
    Thread s = new Thread(ServerThreadProc);
    s.Start();
    using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
    {
        client.ReceiveTimeout = 500;
        client.Connect("127.0.0.1", 12345);
        byte[] buf = new byte[16];
        System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
        try
        {
            watch.Start();
            client.Receive(buf);
        }
        catch (SocketException ex)
        {
            watch.Stop();
            Assert.That(ex.SocketErrorCode, Is.EqualTo(SocketError.TimedOut));
            Assert.That(watch.ElapsedMilliseconds, Is.AtLeast(475).And.AtMost(525));
        }
    }
    Assert.Fail("Should throw when timeout expired");
}

测试结果:

结果消息

预期:大于或等于 475 且小于或等于 525

但是是:1000

测试抛出异常(通过):

public void ThrowsInTime()
{
    System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
    try
    {
        watch.Start();
        System.Threading.Thread.Sleep(500);
        throw new Exception("Sleeping is done.");
    }
    catch(Exception)
    {
        watch.Stop();
        Assert.That(watch.ElapsedMilliseconds, Is.AtLeast(475).And.AtMost(525));
    }
}

有人遇到过这样的问题吗?

【问题讨论】:

  • 我怀疑可能有某种协议交换触发了超时重置。您是否尝试过通过管道发送数据,进行接收以获取该数据,然后查看第二次接收的超时时间是多少?
  • 连接后是否检查了ReceiveTimeout属性的值?
  • 我添加了您的其他建议,但不幸的是它仍然在 1 秒后失败。

标签: c# exception timeout


【解决方案1】:

有几个参考(herehere)接收超时的底层 winsock 实现可能无法按预期工作。它实际上可以实现为大约 500 毫秒加上 ReceiveTiemout 属性的值。尝试将 ReceiveTimeout 设置为不同的值,看看超时是否实际上是 500 毫秒 + 属性值。如果是这种情况,那么您需要在预期超时计算中考虑额外的 500 毫秒。

【讨论】:

  • 是的,这实际上是对投掷增加了 500 毫秒(即,在我看到投掷前 1.25 秒,750 的属性会产生结果)。更有趣的是,当我在 Wireshark 中检查这个时,我会看到最后一条消息,然后在发送 FIN/ACK tcp 消息之前看到超时的延迟加上 500 毫秒。
猜你喜欢
  • 2010-09-30
  • 2018-10-12
  • 2013-03-13
  • 1970-01-01
  • 2011-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-08
相关资源
最近更新 更多