How to continue using a Socket after a timeout?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • carl.rosenberger@gmail.com

    #1

    How to continue using a Socket after a timeout?

    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.SetSocke tOption(
    SocketOptionLev el.Socket,
    SocketOptionNam e.ReceiveTimeou t,
    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.IOExc eption 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?

  • carl.rosenberger@gmail.com

    #2
    Re: How to continue using a Socket after a timeout?

    carl.rosenber.. .@gmail.com wrote:
    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()
    {
    OpenServerSocke t();
    ConnectClient() ;
    AcceptServer();
    ConfigureTimeou t();
    OpenInputStream ();

    CheckTimeoutOnR ead();
    CheckTimeoutOnR ead();

    CloseAll();
    }

    private void CheckTimeoutOnR ead()
    {
    int start = Environment.Tic kCount;
    int stop = 0;
    try
    {
    _inputStream.Re adByte();
    }
    catch (Exception ex)
    {
    stop = Environment.Tic kCount;
    Console.WriteLi ne(ex);
    }

    int duration = stop - start;

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

    void OpenServerSocke t()
    {
    _serverSocket = NewSocket();
    _serverSocket.B ind(new IPEndPoint(IPAd dress.Any, 0));
    _serverSocket.L isten(42);
    }

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

    void AcceptServer()
    {
    _server = _serverSocket.A ccept();
    }

    void ConfigureTimeou t()
    {
    _server.SetSock etOption(Socket OptionLevel.Soc ket,
    SocketOptionNam e.ReceiveTimeou t, TIMEOUT);
    _server.SetSock etOption(Socket OptionLevel.Soc ket,
    SocketOptionNam e.SendTimeout, TIMEOUT);
    }

    void OpenInputStream ()
    {
    _inputStream = new NetworkStream(_ server);
    }

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

    int Port()
    {
    return ((IPEndPoint)_s erverSocket.Loc alEndPoint).Por t;
    }

    Socket NewSocket()
    {
    return new Socket(AddressF amily.InterNetw ork,
    SocketType.Stre am, ProtocolType.Tc p);
    }

    IPAddress Resolve(string hostName)
    {
    IPHostEntry found = Dns.Resolve(hos tName);
    foreach (IPAddress address in found.AddressLi st)
    {
    if (address.Addres sFamily == AddressFamily.I nterNetwork)
    {
    return address;
    }
    }
    throw new Exception();
    }
    }

    Comment

    • Peter Duniho

      #3
      Re: How to continue using a Socket after a timeout?

      carl.rosenberge r@gmail.com wrote:
      [...]
      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/lib...s740476.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

      Comment

      Working...