套接字接收超时会引发延迟异常

时间:2014-04-21 16:06:19

标签: c# exception timeout

在c#中,我有一个非常简单的服务器/客户端。接收到500毫秒时,客户端设置为超时。当它超时时,我希望它会抛出一个异常,然而,它会在500毫秒后捕获它,总计达到一秒。要仔细检查一下,我可能只是一台慢机器,我会测试抛出异常需要多长时间才能正确。这是一些片段。

服务器主题:

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));
    }
}

有没有人看到这样的问题?

1 个答案:

答案 0 :(得分:0)

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