Domanda

In c#, I have a very simple server/client. The client is set to timeout when receiving to 500 ms. When it times out, I expect it to throw an exception and it does, however, I catch it 500ms later which totals up to a total second. To double check that maybe I just have a slow machine, I test out how long it takes to throw an exception it it's about right. Here are some snippets.

Server thread:

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

Testing receive timeout (fails):

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

Results from the test:

Result Message

Expected: greater than or equal to 475 and less than or equal to 525

But was: 1000

Testing throwing an exception (passes):

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

Has anyone see an issue like this?

È stato utile?

Soluzione

There are several references (here and here) to the underlying winsock implementation of the receive timeout may not quite work as expected. It may actually be implemented as about 500ms plus the value of the ReceiveTiemout property. Try setting the ReceiveTimeout to different values and see if the timeout is actually 500ms + the property value. If that is the case then you will need to account for the additional 500ms in your expected timeout calculations.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top