UDP sockets - not getting FD_READ after some time of activity on a socket
-
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 becauseWSAWaitForMultipleEvents
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 -
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 becauseWSAWaitForMultipleEvents
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 cancCould 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?
-
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?
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
-
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
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
-
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
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
-
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
You are welcome!