How to continue using a Socket after a timeout?

C

carl.rosenberger

Hi,

I am trying to get the following behaviour for my Socket connection:

(1) Attempt a blocked read for a defined amount of time.
(2) If a timeout occurs, because no data has been sent to the socket,
throw an exception.
(3) Catch the exception and either go back to (1) or quit reading,
depending on a variety of (user defined) factors.

To implement the above I use:

socket.SetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout,
timeout);

Everything works as expected until the first timeout occurs. When
try to read again after the first timeout, the next exception occurs
immediately, without respecting the timeout setting.

I get a System.IO.IOException with the following Message:
"Unable to read data from the transport connection: A non-blocking
socket operation could not be completed immediately."

Even after I send data to the socket and successfully read data, the
behaviour of throwing an exception immediately when no data is
avaialble does not go away and I never get the socket back to a
state where it obeys the timeout in the read operation.

What am I missing?

Is there some kind of reset button that I can push on a timeout?
 
C

carl.rosenberger

I am trying to get the following behaviour for my Socket connection:

(1) Attempt a blocked read for a defined amount of time.
(2) If a timeout occurs, because no data has been sent to the socket,
throw an exception.
(3) Catch the exception and either go back to (1) or quit reading,
depending on a variety of (user defined) factors.

Following up, here is a simple code sampe to reproduce the issue:

class Program
{

static int TIMEOUT = 1500;


Socket _serverSocket;

Socket _server;

Socket _client;

NetworkStream _inputStream;


static void Main()
{
new Program().Run();
}

public void Run()
{
OpenServerSocket();
ConnectClient();
AcceptServer();
ConfigureTimeout();
OpenInputStream();

CheckTimeoutOnRead();
CheckTimeoutOnRead();

CloseAll();
}

private void CheckTimeoutOnRead()
{
int start = Environment.TickCount;
int stop = 0;
try
{
_inputStream.ReadByte();
}
catch (Exception ex)
{
stop = Environment.TickCount;
Console.WriteLine(ex);
}

int duration = stop - start;

Console.WriteLine("Expected timeout: " + TIMEOUT);
Console.WriteLine("Actual timeout: " + duration);
}

void OpenServerSocket()
{
_serverSocket = NewSocket();
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 0));
_serverSocket.Listen(42);
}

void ConnectClient()
{
_client = NewSocket();
_client.Connect(new IPEndPoint(Resolve("localhost"), Port()));
}

void AcceptServer()
{
_server = _serverSocket.Accept();
}

void ConfigureTimeout()
{
_server.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, TIMEOUT);
_server.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.SendTimeout, TIMEOUT);
}

void OpenInputStream()
{
_inputStream = new NetworkStream(_server);
}

void CloseAll()
{
_client.Close();
_server.Close();
_serverSocket.Close();
}

int Port()
{
return ((IPEndPoint)_serverSocket.LocalEndPoint).Port;
}

Socket NewSocket()
{
return new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
}

IPAddress Resolve(string hostName)
{
IPHostEntry found = Dns.Resolve(hostName);
foreach (IPAddress address in found.AddressList)
{
if (address.AddressFamily == AddressFamily.InterNetwork)
{
return address;
}
}
throw new Exception();
}
}
 
P

Peter Duniho

[...]
Even after I send data to the socket and successfully read data, the
behaviour of throwing an exception immediately when no data is
avaialble does not go away and I never get the socket back to a
state where it obeys the timeout in the read operation.

What am I missing?

Is there some kind of reset button that I can push on a timeout?

No. It's unfortunate that the .NET docs aren't more clear about this;
the Winsock docs do a better job. From the docs for SO_RCVTIMEO and
SO_SNDTIMEO (http://msdn2.microsoft.com/en-us/library/ms740476.aspx):

If a send or receive operation times out on a socket,
the socket state is indeterminate, and should not be used;
TCP sockets in this state have a potential for data loss,
since the operation could be canceled at the same moment
the operation was to be completed.

Don't use the ReceiveTimeout property if you want to be able to use the
socket after the timeout occurs.

I think you will be happier if you adjust your thinking to not treat
your "timeout" as an exception. That is, you don't really have an
exception...you have a time-based monitoring situation in which you want
to perform some specific, configurable action after a fixed amount of time.

So, instead of using the timeout property of the socket, just set up
some sort of timer somewhere that executes code after a fixed amount of
time. Only if the actual behavior you want is to cancel the i/o on the
socket would you then close the socket when the timer goes off.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top