views:

349

answers:

2

I have been messing around Boost Asio for some days now but I got stuck with this weird behavior. Please let me explain.

Computer A is sending continuos udp packets every 500 ms to computer B, computer B desires to read A's packets with it own velocity but only wants A's last packet, obviously the most updated one.

It has come to my attention that when I do a:

mSocket.receive_from(boost::asio::buffer(mBuffer), mEndPoint);

I can get OLD packets that were not processed (almost everytime).

Does this make any sense? A friend of mine told me that sockets maintain a buffer of packets and therefore If I read with a lower frequency than the sender this could happen. ¡?

So, the first question is how is it possible to receive the last packet and discard the ones I missed?

Later I tried using the async example of the Boost documentation but found it did not do what I wanted.

http://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/tutorial/tutdaytime6.html

From what I could tell the async_receive_from should call the method "handle_receive" when a packet arrives, and that works for the first packet after the service was "run".

If I wanted to keep listening the port I should call the async_receive_from again in the handle code. right?

BUT what I found is that I start an infinite loop, it doesn't wait till the next packet, it just enters "handle_receive" again and again.

I'm not doing a server application, a lot of things are going on (its a game), so my second question is, do I have to use threads to use the async receive method properly, is there some example with threads and async receive?

Thanks for you attention.

+3  A: 

One option is to take advantage of the fact that when the local receive buffer for your UDP socket fills up, subsequently received packets will push older ones out of the buffer. You can set the local receive buffer size to be large enough for one packet, but not two. This will make the newest packet to arrive always cause the previous one to be discarded. When you then ask for the packet using receive_from, you'll get the latest (and only) one.

Here are the API docs for changing the receive buffer size with Boost:

http://www.boost.org/doc/libs/1_37_0/doc/html/boost_asio/reference/basic_datagram_socket/receive_buffer_size.html

The example appears to be wrong, in that it shows a tcp socket rather than a udp socket, but changing that back to udp should be easy (the trivially obvious change should be the right one).

Jean-Paul Calderone
Thanks for your answer!In that case I have to know the max udp packet size of each OS?From this page:http://www.29west.com/docs/THPM/udp-buffer-sizing.htmlWindows doesn't have a max... What would you recommend in that case?
Alberto Toglia
Sorry for that, I thought I had to change the Buffer itself.
Alberto Toglia
Are you sure that's the behaviour you'll get? I expect it's a) platform specific and b) not very likely. Rather than the stack doing this work isn't it just as likely to simply throw the NEW datagrams away?? A reference to somewhere that confirms your point of view would be nice.
Len Holgate
I can confirm that on Win7 if I have a UDP socket with a recv buf of 2046 and no overlapped reads pending and I send 3 datagrams of 1022, 1023 and 1024 bytes that when I subsequently post 3 reads I get datagrams 1 and 2, 3 has been discarded... I haven't tried this on Vista or XP, I've only run the test once or twice but it's now in my test harness for my server framework and I'll update the comment if it starts to fail on my various build machines.
Len Holgate
A: 

With Windows (certainly XP, Vista, & 7); if you set your recv buffer size to zero you'll only receive datagrams if you have a recv pending when the datagram arrives. This MAY do what you want but you'll have to sit and wait for the next one if you post your recv just after the last datagram arrives ...

Since you're doing a game, it would be far better, IMHO, is to use something built on UDP rather than UDP itself. Take a look at ENet which supports reliable data over UDP and also unreliable 'sequenced' data over UDP. With unreliable sequenced data you only ever get the 'latest' data. Or something like RakNet might be useful to you as it does a lot of games stuff and also includes stuff similar to ENet's sequenced data.

Something else you should bear in mind is that with raw UDP you may get those datagrams out of order and you may get them more than once. So you're likely gonna need your own sequence number in their anyway if you don't use something which sequences the data for you.

Len Holgate
I have had both libs in mind but I think its an overkill for now. In my specific scenario the order/duplicate packets would not bother much. But what your saying is that calling the receive method with the buffer size in zero would block the app until I get something? In that case I'm leaning towards the async receive, the problem with that is the infinite loop I get into doing it this way http://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/tutorial/tutdaytime6/src.html. Is there a way to have the handler method be called ONLY when a packet arrives?
Alberto Toglia
Well, if it's async then you wont block but you wont get anything until a datagram arrives. I don't use ASIO, I have my own framework that I use (free version on my blog: http://www.lenholgate.com ) but it's more intended for highly scalable, high performance servers rather than a single connection client. Does it need to be cross platform? If not then why bother with ASIO?
Len Holgate
I wonder why this was down voted...
Len Holgate