C#'s Socket.Connect returns normally but socket isn't connected.

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • A. W. Dunstan

    C#'s Socket.Connect returns normally but socket isn't connected.

    I'm creating a socket as follows:

    m_networkSocket = new Socket(AddressF amily.InterNetw ork,
    SocketType.Stre am,
    ProtocolType.Tc p);
    m_networkSocket .LingerState = new LingerOption(tr ue, 1);
    m_networkSocket .Blocking = true;
    m_networkSocket .SetSocketOptio n(SocketOptionL evel.Socket,
    SocketOptionNam e.NoDelay, true);
    m_networkSocket .SetSocketOptio n(SocketOptionL evel.Socket,
    SocketOptionNam e.KeepAlive, !persistentConn ection);

    IPEndPoint them = new IPEndPoint(IPAd dress.Parse(hos tname), port);
    try
    {
    m_networkSocket .Connect(them);
    Debug.Assert(m_ networkSocket.C onnected,
    "Connect() returned but we're not connected! Socket is: " +
    m_networkSocket );
    }
    catch (SocketExceptio n se)
    {
    System.Console. WriteLine("conn ect caught: " + se);
    }

    After writing (synchronously) I close it thus:

    m_networkSocket .Shutdown(Socke tShutdown.Send) ;
    m_networkSocket .Disconnect(fal se);
    m_networkSocket .Close();
    m_networkSocket = null;

    The design requires that I open, write & close the socket for each message
    I'm sending (the network might be unreliable, so a persistent connection
    won't work). The whole thing runs in a single thread, taking messages out
    of a queue (other threads insert messages into the queue).

    The problem I've run into is that this works fine for the first block of
    messages (I've tried batches of 16, 32 and 64 messages, with messages sent
    in rapid succession). This first batch always works. I let a few seconds
    pass, then send another batch. Sometimes the 2nd batch works, sometimes
    not. If it fails it trips on the Debug.Assert immediately after the call
    to Connect().

    If it's returning from Connect() without throwing anything I'd _assumed_
    that the connect worked - but the failure to pass the assertion tells me
    other wise!

    Anybody have any ideas as to what might be going on? I'm somewhat new to
    socket programming, very new to Microsoft. We're using Visual Studio 2005
    on XP Pro SP2.

    thanks

    --
    Al Dunstan, Software Engineer
    OptiMetrics, Inc.
    3115 Professional Drive
    Ann Arbor, MI 48104-5131
  • Peter Duniho

    #2
    Re: C#'s Socket.Connect returns normally but socket isn't connected.

    On Tue, 09 Sep 2008 11:59:51 -0700, A. W. Dunstan <no@spam.thanks wrote:
    [...]
    The problem I've run into is that this works fine for the first block of
    messages (I've tried batches of 16, 32 and 64 messages, with messages
    sent
    in rapid succession). This first batch always works. I let a few
    seconds
    pass, then send another batch. Sometimes the 2nd batch works, sometimes
    not. If it fails it trips on the Debug.Assert immediately after the call
    to Connect().
    >
    If it's returning from Connect() without throwing anything I'd _assumed_
    that the connect worked - but the failure to pass the assertion tells me
    other wise!
    >
    Anybody have any ideas as to what might be going on? I'm somewhat new to
    socket programming, very new to Microsoft. We're using Visual Studio
    2005
    on XP Pro SP2.
    Fundamentally, the issue is that you're relying on a property that isn't
    reliable. It won't return the instantaneous state of the socket, but
    rather the state known at some previous time. Even if it did return the
    instantaneous state, that state could change between the time you check it
    and the time you try to rely on it.

    When Connect() returns, the socket _has_ successfully connected to the
    remote endpoint. However, you can't make any assumptions beyond that.
    The internal data associated with the Connected property might not be
    updated yet or the connection could wind up getting reset immediately
    after connection. You simply need to write your code so that it can deal
    with errors during later operations.

    Speaking of which, given that, it really doesn't make sense to keep
    recreating connections just because of a reliability issue. If anything,
    the extra overhead _increases_ your exposure to reliability issues. Every
    time any data is moved from one endpoint to the other, you run the risk of
    a reliability problem causing an error. The only thing that recreating
    connections does is cause _more_ data to be moved, increasing the risk of
    an error.

    Likewise, using the KeepAlive option will also have only that effect.
    Given that the connections appear to be transient anyway, it's not clear
    why you're using that. But given that you are, all it does is increase
    your chances of having an error occur when one otherwise would not have.
    Keep-alives can be useful in some very specific scenarios, but it's not an
    appropriate approach to error management. That's not what it's there for.

    Setting the Blocking property to "true" is superfluous. That's the
    default.

    Setting the NoDelay option is generally a bad idea, and it is especially
    so in your particular scenario. It's bad generally because it decreases
    efficiency of the connection. It's especially bad in your case for the
    same reason that recreating the connection is: it has the effect of
    _adding_ to the amount of data that needs to be moved, which increases
    your odds of getting an error on the unreliable connection.

    Finally, if you care about reliability, you should not rely on the
    LingerState of the socket. Leave the socket as the default, and then
    after you've called Shutdown(), call Receive() until it returns 0
    (assuming the remote endpoint isn't actually going to send you anything,
    that will happen as soon as the remote endpoint has received all of your
    data). Unless you do that, you have no assurance that the remote endpoint
    has actually received all of the data you sent, even using a lingering
    socket.

    In other words, I would take out almost all of the implementation details
    you've posted, including the part of the design in which a new connection
    is repeatedly reestablished. Just design the code so that it can recover
    gracefully from a reset connection and otherwise leave the socket
    connected. Don't bother with lingering, keep-alives, or disabling Nagle
    (i.e. "NoDelay"), and do make sure you do a true graceful shutdown by
    calling Receive() after Shutdown().

    Right now, the code is written in a way that is likely to maximize the
    number of errors. You're working against TCP, rather than with it.
    That's never a good approach anyway, but especially when you _know_ you
    have an unreliable connection, it's just going to hurt.

    Pete

    Comment

    • Fernando

      #3
      Re: C#'s Socket.Connect returns normally but socket isn't connected.

      im new to .NET too, but the 64 open socket limit has always caused troubled.
      Theres a way to increase ( if this limit still exist ) but i dont remember.
      anyway, just a guess, probably not the right one.

      "A. W. Dunstan" <no@spam.thanks escreveu na mensagem
      news:NfydnVC_bu 03WlvVnZ2dnUVZ_ vninZ2d@speakea sy.net...
      I'm creating a socket as follows:
      >
      m_networkSocket = new Socket(AddressF amily.InterNetw ork,
      SocketType.Stre am,
      ProtocolType.Tc p);
      m_networkSocket .LingerState = new LingerOption(tr ue, 1);
      m_networkSocket .Blocking = true;
      m_networkSocket .SetSocketOptio n(SocketOptionL evel.Socket,
      SocketOptionNam e.NoDelay, true);
      m_networkSocket .SetSocketOptio n(SocketOptionL evel.Socket,
      SocketOptionNam e.KeepAlive, !persistentConn ection);
      >
      IPEndPoint them = new IPEndPoint(IPAd dress.Parse(hos tname), port);
      try
      {
      m_networkSocket .Connect(them);
      Debug.Assert(m_ networkSocket.C onnected,
      "Connect() returned but we're not connected! Socket is: " +
      m_networkSocket );
      }
      catch (SocketExceptio n se)
      {
      System.Console. WriteLine("conn ect caught: " + se);
      }
      >
      After writing (synchronously) I close it thus:
      >
      m_networkSocket .Shutdown(Socke tShutdown.Send) ;
      m_networkSocket .Disconnect(fal se);
      m_networkSocket .Close();
      m_networkSocket = null;
      >
      The design requires that I open, write & close the socket for each message
      I'm sending (the network might be unreliable, so a persistent connection
      won't work). The whole thing runs in a single thread, taking messages out
      of a queue (other threads insert messages into the queue).
      >
      The problem I've run into is that this works fine for the first block of
      messages (I've tried batches of 16, 32 and 64 messages, with messages sent
      in rapid succession). This first batch always works. I let a few seconds
      pass, then send another batch. Sometimes the 2nd batch works, sometimes
      not. If it fails it trips on the Debug.Assert immediately after the call
      to Connect().
      >
      If it's returning from Connect() without throwing anything I'd _assumed_
      that the connect worked - but the failure to pass the assertion tells me
      other wise!
      >
      Anybody have any ideas as to what might be going on? I'm somewhat new to
      socket programming, very new to Microsoft. We're using Visual Studio 2005
      on XP Pro SP2.
      >
      thanks
      >
      --
      Al Dunstan, Software Engineer
      OptiMetrics, Inc.
      3115 Professional Drive
      Ann Arbor, MI 48104-5131

      Comment

      • Peter Duniho

        #4
        Re: C#'s Socket.Connect returns normally but socket isn't connected.

        On Tue, 09 Sep 2008 17:07:15 -0700, Fernando <FatalError0x4c @hotmail.com>
        wrote:
        im new to .NET too, but the 64 open socket limit has always caused
        troubled.
        There is no such limit. Even on Win9x, you could have hundreds of sockets
        open, and the NT-based OSs go _much_ higher than that.

        You may be thinking of the 64-socket limit on WSAEventSelect (due to the
        underlying limit in WaitForMultiple Objects), or in the legacy function
        select. But there are simple ways to code around those, and it's not a
        limit on the actual number of sockets, but just how many any given thread
        can watch at once.

        You'll note also that the OP's issue happens with a variety of numbers of
        connections per "batch", not just 64, and doesn't happen 100% of the
        time. So, I think that the issue here is unrelated to any physical limit
        on the number of sockets and/or connections, inasmuch as any limitation
        even exists.

        Pete

        Comment

        Working...