Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. UDP sockets - not getting FD_READ after some time of activity on a socket

UDP sockets - not getting FD_READ after some time of activity on a socket

Scheduled Pinned Locked Moved C / C++ / MFC
graphicssysadminquestion
6 Posts 2 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    csrss
    wrote on last edited by
    #1

    Hi there everyone. I have some pretty much basic UDP sockets scenario: my app requests data from server and receives requested data. There is a lot of data so there is a cancellation method as well. When I cancel data receiving and request data again, app not getting FD_READ events anymore. Strange thing is, it is not always the same - sometimes there are a couple of FD_READs, sometimes half of the data could be transmitted before it stops, sometimes - none. Code itself is basically the same as anywhere on the net and goes like this: 1. Before any receiving, check if FD_READ is set

    DWORD dwResult =
    ::WSAWaitForMultipleEvents(vecHandles.size(), &vecHandles[0], FALSE, dwTimeout, FALSE);

    - vecHandles is a vector of event handles, which includes my WSAEVENT for triggering cancellation. which is done like this:

    ::WSASetEvent(hEvent);

    So now ::WSAWaitForMultipleEvents will return with my event. 2. Check which event we got: if it is read event, then call recv.

    if( socket_event_read * pReadEvent = dynamic_cast(pSocketEvent) )
    {
    WSANETWORKEVENTS nt = { 0x00 };
    if( SOCKET_ERROR != ::WSAEnumNetworkEvents(pReadEvent->get_socket(), pSocketEvent, &nt) )
    {
    if( nt.lNetworkEvents & FD_READ && nt.iErrorCode[FD_READ_BIT] == false )
    {
    ::WSARecvFrom(...);
    }
    }
    }

    3. Handle data. That's it. It all works great if receiving is never cancelled. Otherwise it just stops at some point while waiting for multiple events (::WSAWaitForMultipleEvents) Again, what I mean is: I hit cancel button and

    ::WSASetEvent(hEvent);

    is called, that causes ::WSAWaitForMultipleEvents to return with my cancel event (WSAWaitForMultipleEvents is called in a loop for every incoming data chunk - each one is about 512kb). And then app just stops receiving - it leaves socket as it is, socket is not closed and still alive. Then I hit a button again for app to begin download data again and that is when app stops receiving packets because WSAWaitForMultipleEvents is waiting for fd_read which is never signaled. Then I hit cancel again, - this is handled properly and then again download data - this time data is downloading ok. This behavior occurs all the time. I am struggling with this for a couple of days now and got completely no idea what is going on, have searched all the net with no result. I have tried checking, when canc

    P 1 Reply Last reply
    0
    • C csrss

      Hi there everyone. I have some pretty much basic UDP sockets scenario: my app requests data from server and receives requested data. There is a lot of data so there is a cancellation method as well. When I cancel data receiving and request data again, app not getting FD_READ events anymore. Strange thing is, it is not always the same - sometimes there are a couple of FD_READs, sometimes half of the data could be transmitted before it stops, sometimes - none. Code itself is basically the same as anywhere on the net and goes like this: 1. Before any receiving, check if FD_READ is set

      DWORD dwResult =
      ::WSAWaitForMultipleEvents(vecHandles.size(), &vecHandles[0], FALSE, dwTimeout, FALSE);

      - vecHandles is a vector of event handles, which includes my WSAEVENT for triggering cancellation. which is done like this:

      ::WSASetEvent(hEvent);

      So now ::WSAWaitForMultipleEvents will return with my event. 2. Check which event we got: if it is read event, then call recv.

      if( socket_event_read * pReadEvent = dynamic_cast(pSocketEvent) )
      {
      WSANETWORKEVENTS nt = { 0x00 };
      if( SOCKET_ERROR != ::WSAEnumNetworkEvents(pReadEvent->get_socket(), pSocketEvent, &nt) )
      {
      if( nt.lNetworkEvents & FD_READ && nt.iErrorCode[FD_READ_BIT] == false )
      {
      ::WSARecvFrom(...);
      }
      }
      }

      3. Handle data. That's it. It all works great if receiving is never cancelled. Otherwise it just stops at some point while waiting for multiple events (::WSAWaitForMultipleEvents) Again, what I mean is: I hit cancel button and

      ::WSASetEvent(hEvent);

      is called, that causes ::WSAWaitForMultipleEvents to return with my cancel event (WSAWaitForMultipleEvents is called in a loop for every incoming data chunk - each one is about 512kb). And then app just stops receiving - it leaves socket as it is, socket is not closed and still alive. Then I hit a button again for app to begin download data again and that is when app stops receiving packets because WSAWaitForMultipleEvents is waiting for fd_read which is never signaled. Then I hit cancel again, - this is handled properly and then again download data - this time data is downloading ok. This behavior occurs all the time. I am struggling with this for a couple of days now and got completely no idea what is going on, have searched all the net with no result. I have tried checking, when canc

      P Offline
      P Offline
      pasztorpisti
      wrote on last edited by
      #2

      Could you please post the code of the whole network loop? This info isn't enough. Send also the code/functions (like cancel) that are used to send signal to your network thread and indicate which thread calls what and what does the network thread does in case of a cancel. BTW, why are you using UPD? You should use TCP to transfer data. In case of UDP you have to implement congestion control and reliability (defense against packet loss) yourself. Is it some kind of real-time data transfer (like audio/video streaming) where data loss is not a problem?

      C 1 Reply Last reply
      0
      • P pasztorpisti

        Could you please post the code of the whole network loop? This info isn't enough. Send also the code/functions (like cancel) that are used to send signal to your network thread and indicate which thread calls what and what does the network thread does in case of a cancel. BTW, why are you using UPD? You should use TCP to transfer data. In case of UDP you have to implement congestion control and reliability (defense against packet loss) yourself. Is it some kind of real-time data transfer (like audio/video streaming) where data loss is not a problem?

        C Offline
        C Offline
        csrss
        wrote on last edited by
        #3

        I think I am going to deal with it myself - code is too big and complicated to post it, or to even take one method from it - it is 1000+ lines custom network framework :( I am using UDP for consistency with discovery mechanisms, which I am implementing in app - it should do a lot of networking, pretty fast, without any user intervention - tcp will not allow me to, - it will force a solution where app will have to be configured by user and I cannot allow it to. I could do discovery only with UDP but I have written huge framework which actually implements TCP partially. Basically, I am not sure when FD_READ gets signaled? When there is data available or when WSARecvFrom can perform read? This would explain why it is not raised... I am going to deal with it on my own - it is too complicated :(

        011011010110000101100011011010000110100101101110 0110010101110011

        P 1 Reply Last reply
        0
        • C csrss

          I think I am going to deal with it myself - code is too big and complicated to post it, or to even take one method from it - it is 1000+ lines custom network framework :( I am using UDP for consistency with discovery mechanisms, which I am implementing in app - it should do a lot of networking, pretty fast, without any user intervention - tcp will not allow me to, - it will force a solution where app will have to be configured by user and I cannot allow it to. I could do discovery only with UDP but I have written huge framework which actually implements TCP partially. Basically, I am not sure when FD_READ gets signaled? When there is data available or when WSARecvFrom can perform read? This would explain why it is not raised... I am going to deal with it on my own - it is too complicated :(

          011011010110000101100011011010000110100101101110 0110010101110011

          P Offline
          P Offline
          pasztorpisti
          wrote on last edited by
          #4

          The main loop of your network thread that handles the send and receive should be relatively small and should be kept together in a small place separated from the other parts of the code. If this critical piece of code is not coupled well separated from your higher level logic, then you should refactor it. This piece of code should handle just raw outgoing and incoming packets on the network thread and all the logic should be implemented separately on top of this layer. A low-level data recv/send loop implementation should be around 100-200 lines of code and all it knows is sending bytes/packets from your send queue, receiving them into a recv queue (and notifying your high level handlers) and exiting when your application exits.

          if( socket_event_read * pReadEvent = dynamic_cast(pSocketEvent) )
          {
          WSANETWORKEVENTS nt = { 0x00 };
          if( SOCKET_ERROR != ::WSAEnumNetworkEvents(pReadEvent->get_socket(), pSocketEvent, &nt) )
          {
          if( nt.lNetworkEvents & FD_READ && nt.iErrorCode[FD_READ_BIT] == false )
          {
          ::WSARecvFrom(...);
          }
          }
          }

          For example here your application logic and the a part of your raw network data receiver logic is already mixed that is bad and dynamic_cast is always the indicator of some hacks and bad OO design that needs refactoring. We don't even know when does that dynamic_cast result in a non-null pointer... It seems that you have a big bunch of refactorable code that you will be fixing till the end of your life without a rewrite (and it is worth rewriting stuff... :-)) BTW, there is another thing that came to my mind regarding WSAWaitForMultipleEvents: FD_READ is level triggered but FD_WRITE is edge triggered and many guys get confused of this. This means that waiting for an FD_READ is safe even if you wait for it twice without reading anything from the socket. The event isn't cleared until data is available for read in the recv buffer of the socket. But FD_WRITE is edge triggered: If you receive an FD_WRITE event then you must assume that FD_WRITE is set until your write fails with EWOULDBLOCK. Receiving an FD_WRITE event clears the FD_WRITE event immediately and it will be set again only when the send buffer of the socket transitions from full to non-full next time. If you try to wait for an FD_WRITE without writing all the available buffer space by receiving EWOULDBLOCK then you will wait for FD_WRITE forever! Depending on how you handle WSAEventSelect and WSAWaitForMultipleEvents your logic can g

          C 1 Reply Last reply
          0
          • P pasztorpisti

            The main loop of your network thread that handles the send and receive should be relatively small and should be kept together in a small place separated from the other parts of the code. If this critical piece of code is not coupled well separated from your higher level logic, then you should refactor it. This piece of code should handle just raw outgoing and incoming packets on the network thread and all the logic should be implemented separately on top of this layer. A low-level data recv/send loop implementation should be around 100-200 lines of code and all it knows is sending bytes/packets from your send queue, receiving them into a recv queue (and notifying your high level handlers) and exiting when your application exits.

            if( socket_event_read * pReadEvent = dynamic_cast(pSocketEvent) )
            {
            WSANETWORKEVENTS nt = { 0x00 };
            if( SOCKET_ERROR != ::WSAEnumNetworkEvents(pReadEvent->get_socket(), pSocketEvent, &nt) )
            {
            if( nt.lNetworkEvents & FD_READ && nt.iErrorCode[FD_READ_BIT] == false )
            {
            ::WSARecvFrom(...);
            }
            }
            }

            For example here your application logic and the a part of your raw network data receiver logic is already mixed that is bad and dynamic_cast is always the indicator of some hacks and bad OO design that needs refactoring. We don't even know when does that dynamic_cast result in a non-null pointer... It seems that you have a big bunch of refactorable code that you will be fixing till the end of your life without a rewrite (and it is worth rewriting stuff... :-)) BTW, there is another thing that came to my mind regarding WSAWaitForMultipleEvents: FD_READ is level triggered but FD_WRITE is edge triggered and many guys get confused of this. This means that waiting for an FD_READ is safe even if you wait for it twice without reading anything from the socket. The event isn't cleared until data is available for read in the recv buffer of the socket. But FD_WRITE is edge triggered: If you receive an FD_WRITE event then you must assume that FD_WRITE is set until your write fails with EWOULDBLOCK. Receiving an FD_WRITE event clears the FD_WRITE event immediately and it will be set again only when the send buffer of the socket transitions from full to non-full next time. If you try to wait for an FD_WRITE without writing all the available buffer space by receiving EWOULDBLOCK then you will wait for FD_WRITE forever! Depending on how you handle WSAEventSelect and WSAWaitForMultipleEvents your logic can g

            C Offline
            C Offline
            csrss
            wrote on last edited by
            #5

            Thanks for your suggestions :) Well, I knew about fd_write thing ;) Part about critical section got me thinking for sure - that is something I haven't considered in current implementation. Anyways, thanks very much, I need a moment to think about all this.

            011011010110000101100011011010000110100101101110 0110010101110011

            P 1 Reply Last reply
            0
            • C csrss

              Thanks for your suggestions :) Well, I knew about fd_write thing ;) Part about critical section got me thinking for sure - that is something I haven't considered in current implementation. Anyways, thanks very much, I need a moment to think about all this.

              011011010110000101100011011010000110100101101110 0110010101110011

              P Offline
              P Offline
              pasztorpisti
              wrote on last edited by
              #6

              You are welcome!

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • World
              • Users
              • Groups