How to write safe UDP socket programs?
Michael Faerber

I have heard that TCP network sockets were slower than UDP and that you had to use UDP for network broadcasts, so I thought about switching to UDP in my network library.

Problem is, that UDP seems to have no guarantee that a message is really sent. So I wanted to ask you if you knew a system to guarantee that complete messages are sent and received.

HoHo

you write your own wrapper protocol around UDP.
Perhaps this helps a little.

Michael Faerber

Thanks for your link, but desperately, the headline says it all: Low level Nonsense and Network Theory! I would be happy about a code snippet implementing an existant protocol wrapper.

Frank Drebin

can't you use both tcp/udp at the same time - so tcp for the important packages and udp for the rest
btw: you know how tcp works then take a look at beejs guide and adjust your code - i think udp isn't that different

HoHo

Guess what I found after googling for "reliable udp code"'
A UDP-based Reliable Data Transfer Library

Well, technically I didn't find it via google, the third link it gave was broken but searching reliable udp from codeproject gave that.

Michael Faerber

Frank: My network library's design is much more like UDP (although it uses TCP), so I think it's just logic that I will use UDP from now. But I could make abstract classes, which would allow me to use both systems.

HoHo: Thanks for this link, I've downloaded the source and will have a further look at it!

EDIT: I looked at the source code and it seems to take some time to understand it. Does nobody have a small source file?

A J

HawkNL, has reliable (TCP), unreleiable(UDP) ,and something called reliable packets (UDP with reliablity code).

gering

RakNet uses UDP with reliablity code.

Michael Faerber

I know of these libraries, but the basic question (the question of life ;) ) is: How can the peers (clients and servers) know, whether packets have been sent correctly or not? Does nobody know this?

HoHo
Quote:

How can the peers (clients and servers) know, whether packets have been sent correctly or not?

With UDP they can't.

Michael Faerber

What? Before, you said I should write a wrapper protocol around UDP to guarantee that packages are sent completely. To send complete packages, I must know whether the package has arrived. So if I don't know if a package has been received, guaranteed package sending is impossible!! ???

HoHo

example:

You put and ID(serial number) into each packet.
Reciever reads all the packets and if in one second a packet with ID X is missing it requests it from server again.
If a response is not recieved in one second another request is sent.

[edit]
If such system is done you can call it your reliable wrapper around UDP

Frank Drebin

and that's why i think it's a good idea to use tcp (at least) too.

Michael Faerber

But what advantages has TCP over UDP (when you have successfully implemented an UDP wrapper)?

Frank Drebin

it is reliable...
if a player moves and this packet is lost - no problem (UDP)
if a player shoots a bullet - this packet must arrive (TCP)

HoHo

But UDP has much shorter latency ;)

[url http://www.flipcode.com/articles/network_part07.shtml]
Network Game Programming - Issue 07 - I bent my Wookie...[/url]

Quote:

TCP vs. UDP (continued)

TCP is a simple and effective way of transmitting data. For making sure that your client and server can talk to each other it is very good. However, it carries with it a lot of overhead and extra network lag so once you feel you are ready you should make the jump to UDP. The big problems you will face with UDP include:

# You won't have an individual socket for each client. In fact FD_ACCEPT will never be called. There won't be any clear notice that the client now sending you data wants to join the game unless you make the client say as much.
# Given that clients don't need to open a unique socket in order to transmit data there is the very real possibility that a client who is not logged into the game will start sending all kinds of garbage to your server in some kind of attack. It becomes much more difficult to stop them at this point.
# Likewise, you won't have a clear disconnect/leave game message unless you write one yourself.
# Some data may not reach the other machine, so you may have to send important stuff many times.
# Some data may arrive in the wrong order. Imagine that you got snapshot 5 before snapshot 4. Snapshot 4 would have to be suppressed (rejected).

While switching to UDP will get you a signifigant speed boost, there are a few more tricks you can try.

BAF

Use enet (I tried and recommend it) or raknet (heard it was good) ?

orz

It seems like this is coming up a lot lately.

UDP and TCP have the same latency, if you adjust the TCP settings for low latency. If you use default settings, TCP can have up to twice the latency of UDP. Note that this comparison assumes the network has no packet loss... if there's packet loss the comparison is more complicated, and TCP may fare worse.

TCP has NO advantage over UDP + a good wrapper, except that TCP is a standard. TCP is more or less THE standard implementation of UDP + wrapper. The advantage of reimplementing the wrapper yourself is that you get to optimize the wrapper for your particular purposes, or concievably even do a better job than the TCP designers did.

amarillion
Michael Faerber

How to adjust settings for TCP to have lower latency?

gillius

Some notes:
AJ: NL_RELIABLE_PACKETS works over TCP. There is no reliable-UDP implementation in HawkNL. What NL_RELIABLE_PACKETS does in HawkNL is to simulate discrete packets as you see in UDP but in TCP. Since TCP is a stream, you can't be guaranteed that one send matches one receive. NL_RELIABLE_PACKETS puts packet boundaries into the stream to break up the stream as it arrives to make sure you get the "packets" as you sent them.

orz is right in his implication that any general wrapper for reliable UDP is not beneficial. TCP guarantees delivery and ordering, and it does this with a lossy datagram-oriented protocol (IP). UDP is not much more than adding the concept of ports to IP and is pretty much raw IP, which TCP is built upon.

The benefit to using UDP reliablity layers is if you want some but not all of the features given by TCP:

  • Reliable data transmission

  • Stream-based transmission

  • ordered data transmission

  • socket multiplexing through the same port (good for firewalls)

</li>
So, for example if you want reliable, packeted, and unordered data transmission, it should not be hard to "beat" TCP by using UDP with a reliability layer.

If you are unconditionally implementing all of the five features above with a reliable UDP layer, then there won't be an advantage over TCP except that the TCP layer in your OS is probably more tested than your code ;).

orz

Adjusting TCP for low-latency stuff:

The most important thing is to disable packet-combining (aka Nagle algorithm). If you don't do this, it wont send any data until either all previous packets have been acknoledged or the send buffer contains a lot of data.

  int tmp = 1;
  setsockopt ( sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&tmp, sizeof(tmp));

I think it's also a good idea to reduce the size of the send buffer if your programs bandwidth usage varies based upon how much is available. If you're writting a game that uses a fixed amount of bandwidth then this is not useful. It's done like this:

  tmp = 2048;
  setsockopt ( sock, SOL_SOCKET, SO_SNDBUF, (const char *)&tmp, sizeof(tmp));

On some operating systems it may also be a good idea to adjust "low water thresholds", but I'm not sure about that, they can't be adjusted on windows, and I think they default to good values on linux, so it's pretty much irrelevant.

Michael Faerber

orz, many thanks for this function! This will probably save me a lot of time!

I just have one question: If I disable the Nagle algorithm, I probably won't have to reduce the send buffer, because I send everything immediately anyway, don't I?

orz

If the Nagle algorithm is disabled, it won't delay anything for the purpose of improving bandwidth efficiency. But it will still delay things for the purpose of throttling the connection down to the available bandwidth.

i.e. If you send some data, and the send buffers are small, then the socket will then be not-ready-to-send, as in, if you select with only that socket in the write set, and no read or except set, then select will block if there's a timeout or return 0 if there's not, and remove that socket from the set. This is the desired behavior in low-latency variable-bandwidth games.
If you send some data, and the send buffers are large, the socket will still be ready-to-send, as in, if you select with that socket in the write set then select will not block and will return a positive number and leave that socket in the set.

If you are confident that available bandwidth is large compared to used bandwidth, you don't need to worry about that. If you have no ability to vary the bandwidth usage for your game, then there's not much point in worrying about it, any clients without enough bandwidth are doomed anyway. But if your games uses variable bandwidth, you need to know when to stop sending, otherwise the buffers will fill up with older data that may be optional anyway, and newer data that's mandatory will get delayed waiting for the older data to finish.

Or at least, that's my understanding.

Thread #525936. Printed from Allegro.cc