Reliable UDP/IP Techniques

Started by
22 comments, last by Null and Void 19 years, 12 months ago
Ok, my UDP/IP is now working. I know that UDP isn't guaranteed to arrive in any order or at all, so I was wondering what techniques are commonly used to ensure packets arrive? I could probably design my own, but I know it wouldn't be efficient or pretty. I looked around online, but all I could find was discussions about how UDP isn't reliable (I already know that ). BTW: I'm using WinSock 2.2 at the moment, and I won't use DirectPlay because I want to port my game and WinSock is a whole lot more like BSD/Berkley sockets than DirectPlay . Thanks in advance. This thread was resurrected by davedx on April 16, 2004. His post is near of the bottom of this first page. [edited by - Null and Void on April 22, 2004 3:30:10 AM]
Advertisement
Reliable UDP is impelemented much like how TCP is implemented. With each packet you have assign it an id. That id tells you its sequence with respect to the stream, and acts as a unique identifier if it gets dropped.

On the reciver side you recive these packets. After a set wait period (calculated based upon latency and other factors) you send the sender the packet ids which you have recived. You can''t send the packets you haven''t recived becuase you dont know if either there weren''t any packets sent or they all got dropped, so you send the ones which you have recived. Of course its possible this ack packet could be loss, if so then on the senders side, a complete resend will occur. So assuming the ack is not lost, the sender recived the list of sent packets. It then sends packets which were loss. That''s the gist of it.

If you use this reliable UDP stream with respect to packet boundaries, you can ignore the stream consistency and use the packets as they arrive. It will give you lower transcational latency with respect to packet loss. If not then you will suffer the same behavior which TCP streams have when there is loss, high latency. That is if you want to use the reliable UDP like a data stream, the sequenece must be complete before you can send it to the application. That means waiting on packet resends. If that is the case, might as well go with TCP. However if you know that the packets are independent of each other, and can be processed as they come in, you don''t need to wait on resends.

Good Luck

-ddn




Making UDP reliable can be a project. Like the game SubSpace, I would suggest that you _expect_ to have packets lost and (perhaps) ignore packets that are out-of-order (ie, older than other packets you have already received) since the information would be out-of-date (so to speak!)

Games like SubSpace allow a certain percentage of "Packet Loss"; I think anything over 2.5% (or heavy lag) will cause the player to be kicked into a "spectator" mode.

For Massively Multi-Player arcade-type games, SubSpace is the BEST model and working example I have seen yet. Also, it''s become a bit more mature (it''s been around several years now). Even better, the game-play is addictive and (now) free. If you''ve already played it, then you know what I mean. If not, I would highly suggest that you check out www.subspace.net and try out the game.. You can get a lot of good ideas from it.

Cheers!
// CHRIS
// CHRIS [win32mfc]
DDN, when I said reliable UDP I meant just a way to verify that a packet arrived, not to keep them in the same order. If I were trying to keep them in the same order (like you said) I should just use TCP.

Win32mfc, I'm only going to be using reliable UDP for some of the packets, not all of them. Most of my network idea relies on no needing every packet, but for some of the login and logoff stuff I don't want to have any packets being lost. Would having a TCP port AND a UDP port at the same time (on the server), and TCP port for login and UDP for everything else (on the client) be a good idea? Yeah, I've played Sub Space before, it is pretty well done .

Edit: cleaning up old signatures as long as the thread is revived.

[edited by - Null and Void on April 22, 2004 3:32:01 AM]
The method i outlined above does both. I just mentonied that if you want to keep them in sequence you can use the id for that as well.

-ddn
Yeah, I understood what you meant . Ok, here's my idea on implementing this taking into account what I've been told so far. I think I'll add some stuff to it while I'm at it, so this is going to be my own delusional networking system type of thing. I'm typing it up as much for myself as any other reason .



Server:
Each connection will have an unsigned long counter for both received, sent, and last-received packets. They will be initially (when a user just connects) set to zero.

Each time a reliable UDP packet (but not an unreliable UDP packet) is received, this packet's ID (stored within it of course) will be tested against this received counter. Then an unreliable UDP packet will be sent saying that the packet was received (with its number contained within it). And the received counter is incremented by one. Of course the last received will be updated with its ID.

Each time a reliable UDP packet is received that "must be in order" also, it will be cached until the last received counter is equal to one less than its ID number. At the time of caching, a unreliable UDP packet will be sent out with its ID number saying that it was received. Next time a packet is asked for, it will be returned, and the received counter will be incremented one.

Any time any variety of reliable UDP packet is sent, the ID number will be that of the send counter. Then the sent counter will be incremented. It will be cached (also) wholly until a message that says it has been received is found. If a acknowledgement message isn't received, then it will be resent after some odd amount of time.

(This stuff I've already messed around with, but I figure I'd through it in here as long as I'm writing all this up) Also, the server will send out "ping" packets occasionally. Each time a ping packet is sent out, the "AliveStill" counter of that client will be decreased by one. Each time a "pong" packet is received, the client's AliveStill counter will be restored to its original value (what ever that may be).

Client:
The client will be much the same as the server, except that it must store only one sent and receive counter, and doesn't need to send out ping packets, only process them.



Hows that sound?

Edited by - Null and Void on April 26, 2001 9:13:34 PM

Edit: cleaning up old signatures as long as the thread is revived.

[edited by - Null and Void on April 22, 2004 3:32:59 AM]
There''s really no need for ping packets unless you''re sending&expecting very little data. Just disconnect the client if you haven''t received any packet for more than say 30 seconds. Of course, if you''re writing a turn-based network game or something where there''s little traffic you''ll have to send pings.

Apart from that, everything looks fine. I''m pretty sure you''ll have to change something anyway once you got some real-life experience with your networking...

cu,
Prefect

Resist Windows XP''s Invasive Production Activation Technology!
One line of sourcecode says more than a thousand words.
Widelands - laid back, free software strategy
Yeah, I've rewritten my TCP/IP class three times now, and this will be my second UDP/IP one (the other one had no real features, but it worked).

You're probably correct about the pinging, I should probably have it not send ping packets unless a packet hasn't been received in a while, and each time a packet is recieved will "refill" their connection counter.

Edit: cleaning up old signatures as long as the thread is revived.

[edited by - Null and Void on April 22, 2004 3:31:40 AM]
Search for "Sliding window protocol". It''s a common way to do reliable UDP.
Why not just give every package a little max timeout and tell the Client that every max_timeout at least one package has to be sent. If no package was received for max_timeout send a request for the next packageindices that are missing on the receivestack.. So you won''t need any extra bandwidth for packages that were received. (There are more packages that get to their destination than packages that are lost :p). The Sender buffers a stack with the the packages that were sent in the last whatever timeout and so it can resend the package on request. If the package already was deleted, it sends a message to the receiver that the index of the completly lost package is supposed to be ignored or whatever.

I''d like to hear comments about my Ideas!

cya,
Phil

Visit Rarebyte!
and no!, there are NO kangaroos in Austria (I got this questions a few times over in the states
Visit Rarebyte! and no!, there are NO kangaroos in Austria (I got this question a few times over in the states ;) )

This topic is closed to new replies.

Advertisement