UDP Protocol

Started by
4 comments, last by hplus0603 12 years, 10 months ago
I've created a server and a client application. I'm running the server one on my PC with outer IP, connecting to it from any other place is easy. However the machine I test the client on is behind a router and has inner IP. When I send the packet from the client to the server everything works fine. Trouble starts when I want to send the packet to the client with reply - it just won't get delivered.

From what I've got so far, the packet header contains the router outer IP address. So I've created a function in the client that gets the inner IP using ipconfig (Windows cmd), parse the result file. Works great, I have both addresses. Question is: How can I tell the router to send the packet it receives to that given inner IP address? Is there something I have to add in the packet header?

I'm using SDLNet if that is of any help. I know it can be done using TCP, too bad I didn't when I started the app. I'm also curious how it get's done, because from what I've read / heard many online games use this protocol. There has to be a way, I don't really think they'd be leaving so many players without a chance to play.

Thanks in advance.
Advertisement
You cannot instruct the router to do such a thing. It wouldn't make sense anyway, as the server could also be on an internal network with the same IP range and it would send the packet to a machine on this local network - assuming the packet wasn't dropped en route (some/all ISPs check that outgoing packets use their IP ranges to mitigate IP spoofing).

You are correct, most action games use UDP. It does work with most NAT setups. If the client initiates contact, and the server responds to the same IP:port that the client contacted it on, it should work. Note that sending to a different port (or a specific port) on the client would not be likely to work. Networking protocols usually let the client pick an arbitrary port (most APIs allow you to use port 0 to mean a random port), you should not assume the client is using a given port.

Try using tools like wireshark to determine where the packet is being dropped. When debugging network problems and you've exhausted the "obvious" places, try temporarily disabling any security infrastructure (e.g. firewalls on computers or routers) that might be silently dropping the packet.
My client application already sends on a random port, I've just assumed it will be easier to set a specific port for receiving. Seeing as that doesn't work I should use one port for both send and receive? In the packet header I receive on the server-side I'd have the address to send back on and everything should work?

Question is, why not specific port then. Assuming the client contacted the server on a specific port instead of random one, lets say 1234 (random number). If client contacts the server from port 1234 (hard coded in the app) then would the sending back to that port work? Or does it have to be random port?
The client should use one random port. The server should use one known port. Multiple ports cause trouble with NAT.

Read up on how NAT works. In a nutshell, when the computer behind the NAT sends a packet through, the NAT creates a new, random external port to forward the packet on. It maintains a table of <external port, internal IP:port> pairs. If a packet is responded to (sent to the routes external IP and to one of the ports mapped in its table) then it will allow the packet inside the network. If you try send a packet to an arbitrary port on the router, without the client initiating contact or setting up port forwarding, the packet will be dropped.

The client port technically doesn't have to be random, but for practical reasons it must be. First of all, it means that your application will not work if that port is in use (and other client applications do pick random ports, so it could be in use!). Secondly, you can consider the NAT to be some kind of port randomiser anyway, even if the client is using known ports the NAT will not necessarily "respect" these values when it is picking external port numbers. Also consider if you have multiple clients behind a NAT - of necessity they must be mapped to different external ports to work.
Much clearer now, thanks. Leaves me with 1 more question: What happens when there's let's say 10 clients behind a NAT and 2 of them random the same port? Will the router manage? Or do I have to handle such an event in the client app (if so, how to detect it?).

Much clearer now, thanks. Leaves me with 1 more question: What happens when there's let's say 10 clients behind a NAT and 2 of them random the same port? Will the router manage? Or do I have to handle such an event in the client app (if so, how to detect it?).


If two clients are behind the same NAT, the router will not allocate the same external port for both clients.

As a server, you should bind to a known port, on a known address, and receive packets using recvfrom().
recvfrom() will tell you the address you should reply to. This will generally be the external IP/port combination of each client.

As a client, you should just create a socket, and call sendto() to the server ip:port.
The first time you do this, the UDP implementation will bind to some random port on the local machine.
That same port will be re-used for eacn successive sendto().
The NAT gateway between the client and the server will map that inner ip:port to some UNIQUE outer ip:port, which is visible to the server.
For all intents and purposes, that outer ip:port is "the address of the client" for the server.

There is one special case: If the server and the client are behind the same NAT gateway, some NAT gateways do not do "hairpin" NAT where they will allow an inside-initiated connection to an inside-exposed server. This is mainly the case when you use NAT punch-through for user-hosted servers.
The solution to that problem is to discover that the client and the server are on the same network -- for example, by the server's public and private IP both being available in discovery, and each client trying the internal IP first. Might want to use some random session ID as part of that protocol, too, to make sure it doesn't get confused with other things running :-)

enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement