views:

304

answers:

5

Hi,

I have a network software which uses UDP to communicate with other instances of the same program. For different reasons, I must use UDP here.

I recently had problems sending huge ammounts of data over UDP and had to implement a fragmentation system to split my messages into small data chunks. So far, it worked well but I now encounter an issue when I have to send a lot of data chunks.

I have the following algorithm:

  1. Split message into small data chunks (around 1500 bytes)
  2. Iterate over the data chunks list and for each, send it using sendto()

However, when I send a lot of data chunks, the receiver only gets the first 6 messages. Sometimes it misses the sixth and receives the seventh. It depends.

Anyway, sendto() always indicates success. This always happen when I test my software over a loopback interface (127.0.0.1) but never over my LAN network.

If I add something like std::cout << "test" << std::endl; between the sendto() then every frame is received.

I am aware that UDP allows packet loss and that my frames might be loss for a lot of reasons and I suppose it has to do with the rate I am sending the data chunks at.

What would be the right approach here ?

  • Implementing some acknowledgement mechanism (just like TCP) seems overkill.
  • Adding some arbitrary waiting time between the sendto() is ugly and will probably decrease performance.
  • Increasing (if possible) the receiver UDP internal buffer ? I don't even know if this is possible.
  • Something else ?

I really need your advices here.

Thank very much.

Additional information as requested

The reason I must use UDP is because I have several constraints:

  1. TCP doesn't work well with NAT traversal (at least without a specific configuration)
  2. Some messages can be lost. Some others can't.
  3. The message delivery order doesn't matter.
+1  A: 

Implementing an acknowledgement mechanism sounds like exactly what you need to do. That way you can ensure that no more than N packets are "in-flight" at once, and you can retransmit packets that have gone unacknowledged for too long.

caf
Thanks for your answer. Do you have any advices regarding the algorithm I should use ? I guess sending one ackownledgement for each received chunk is suboptimal.
ereOn
As others have said, it's really going to depend on the specifics of your requirements. Sending one acknowledgement for each recieved packet is likely to be fine (the acknowledgements will be small), at least as a first cut.
caf
Requiring 1 ack for every packet before you send the next can be _very_ sub optimal. Say the RTT is 25ms. You can then send only 1 message every 25 ms, if your packets are max sized at 1500, that's 60kb/sec - not very fast if you require speed.
nos
I ended up implementing a per-packet acknowledgement mechanism. It works fine, and without any speed loss. (I don't need delivery order to be respected so I can send messages/acknowlegdements asynchronously, thus avoiding the issues @nos suggested).
ereOn
A: 

TCP exists to solve exactly this kind of problem. Why isn't TCP an option? You are going to have to solve all the same problems and ultimately end up with the same solution, only without the benefit of decades of research, development and debugging of the TCP stack.

If you really must use UDP, the first question to ask is, what are you willing to give up with respect to TCP's guarantees? Are you happy to receive packets out of order? Is it OK to lose some percentage of packets? Can you handle the arrival of duplicate packets? The answers to these questions will hopefully lead to a design.

Without knowing your specifics, it is impossible to answer your question with a simple, "Do this and you'll be fine," except, of course, "Do TCP and you'll be fine".

Marcelo Cantos
Thank you for your answer. I added more information at the end of the question.
ereOn
+1  A: 

You should implement acknowledge, and retransmission. Require e.g. acks for every N packets, and keep N packets in your retransmission buffer.

(maybe you can get some ideas from rudp, or implement Il over UDP )

UDP is unreliable, and also provides no flow control. The short story is, you will lose packets every now and then - especially if you send data fast - the kernel or any routers/switches in between will drop packets if there's not enough space - and there's little magic you can employ to not make that occur.

nos
A: 

UDP transmits datagrams, and is unreliable.

TCP transmits data streams, and is reliable.

What you want appears to be datagram based, but reliable. So you need to build something onto either UDP or TCP to give you that. I am sure there are complete protocol specs building onto UDP that provide just that. You only have to find and implement them.

ndim
+1  A: 

If you are losing packets over the loopback interface after sending only 6 or 7 packets, then it sounds like maybe your receive buffer is too small. You can increase the size with setsockopt using the SO_RCVBUF option. However, if you are sending 1500 bytes, then if this is indeed the issue, it means the receive buffer is only about 9K (or more likely 8K, however that seems a rather small default). I believe on Windows the default receive buffer is 16K.

Even assuming increasing the receive buffer helps, you still have to address the issues others have mentioned. A couple other things to consider is maybe to try to dynamically determine the max packet size to avoid fragmentation. Also, it may make sense to make the packet size and number of packets sent between acks configurable manually.

Mark Wilkins
+1 because you're the only one that spoke about the SO_RCVBUF option.
ereOn