UDP Client and Server on same Computer

Started by
6 comments, last by NastyPasty 19 years, 1 month ago
Hi all, I basically wish to clear a few unknowns and queries I currently have. I am making a game as a personal project, this game will be solely network based. The way I have designed it is like so: It supports UDP and TCP protocols, TCP for sending "important" messages and UDP for frequent updates. I am testing it by building a client and a server one the same computer (2 seperate applications), which is generally quite acceptable as it should be able to cope with both a server and a client. The problems are arising with the use of the UDP protocol. As you know the recvfrom() call must be preceeded by a bind() or a sendto() to 'connect' the socket temporarily. The server will bind() to a particular port and so can sendto and recvfrom whenever it likes. The server should then send out updates to all the clients at a rate of say 10fps. How can the client recv these messages using recvfrom()? It has to call a sendto() before it can use the recvfrom(), this is where I am lost. Am I supposed to send a dummy message to the server just so i can recieve my updates? How does the likes of Quake3 handle this? One solution I thought was to bind the Client as well, which works really well, it means I can use recvfrom() any time I like. One, people frown upon this method, if they do what other solution is there? When running both the client and the server on the same computer posses another problem. There is no problem using the bind as it is just preceeded by a setsockopt() call using SO_REUSEADDR which allows me to use the same port again. But the client always recieves its message back on the next call to recvfrom(), futhermore the server doesn't get a chance to recieve the message (infact it appears to do nothing). This is due to the fact two applications are bound to the same port and the client has focus therefore recieving the messages. I found this rather difficult to explain, so appologies if some things are unclear or if I've repeated. Basically I need some assistance with the idea of running a UDP server and a client on the same computer, or generally your ideas, thoughts or suggestions as to what I should be doing, or should not be doing. Thanks in advance, I hope someone out there can help! :) Dave
Advertisement
solution the first:

have the server accept connections on port: 4353 (random number)
have the client accept connections on port: 4251 (random number)

solution the second:

only the client ever creates connections. the server just listens on a given port. when the client creates a connection it's just kept open for server updates. IMHO, this is a better solution because a lot of clients are behind firewalls and cannot accept connections of any kind anyway. requiring the client to be able to receive connections will thus make a huge number of people completely unable to play your game.

if you are using the same computer for both client and server you just use 127.0.0.1 as the IP address which is the localhost address. Since only the server has a bound listening port, there should be no problems.

-me
Thanks for the suggestions, I'll give it some further thought. I am trying to stay away from using different ports for the client and the server, although for testing on the same computer I suppose it is feasible.

Are you aware of how published games such as Quake3, Unreal Tournament etc handle this? Do all the clients initiate the connection with the server? I was under the assumptions game servers operated at like 10~20fps, this being the rate at which it sent updates out to the clients?

Again thanks,

Dave
Quote:Original post by NastyPasty
Are you aware of how published games such as Quake3, Unreal Tournament etc handle this? Do all the clients initiate the connection with the server? I was under the assumptions game servers operated at like 10~20fps, this being the rate at which it sent updates out to the clients?


yes, all the clients initiate connections with the server. If multiple connections are needed, then the client will have to open them all. You really can't ask the client to listen on any port because odds are that the client is behind some kind of firewall/NAT. That's for a game anyway: easy consumer experience, etc.

Ther are certainly applications out there that prefer if you can receive an incoming connections (like bittorrent). They are generally more techy oriented programs as they require the user to muck with the permissions/settings of their firewall/NAT.

Initiating a connection just means opening a connection. Then you just keep it open through many frames. It's been a while since i've done network coding, but i think that once you have an open socket you can just do a recv on it, even if it wasn't opened as a listen socket... So basically:

client opens socket with a hello to the server
server holds connection around
when server needs to update client, it just sends it down the pipe
client is just listening on that socket.

If i've got that totally wrong, please don't crucify me. That's just how i remember it working. =)

-me
The server must somehow be assigned an UDP port to reply on. A client's can allocate such a (ephemeral) port locally by binding port 0 or calling sendto, however due to NAT it's impossible to predict which port the server will see. There's also no guarantee that an UDP connection can be established just because a TCP connection could.

So the client has to send an identification message through UDP first.
This doesn't have to be very complicated though, since you've already got TCP connection to work with.
The first thing the server should send over the TCP connection should be some unique client ID number (the local incoming TCP port is a good choice). Now, when the client recieves this packet it can begin sending UDP connection requests containing the ID so that the server knows which client is attempting to connect. And once the UDP message has been received by the server it can send an acknowledgement back through the TCP socket to inform the client of that they've been successfully connected and can begin using the port.

That's one way of doing things anyway.
0. Server creates a TCP and an UDP socket on two publicly know ports.1. Client attempts to connect to the server through TCP.2. Server accepts the client's TCP connection and sends back an ID number.3. Client receives its ID and sends it back in its first UDP packet containing it.4. Server receives and acknowledges this packet through TCP.   It now knows which UDP port to use for sending messages back to the client   (returned by recvfrom when retrieving this message).   The server now considers the combined TCP/UDP link open. 5. Client receives the server's acknowledgement. And the client can begin using the TCP/UDP link.
Quote:Am I supposed to send a dummy message to the server just so i can recieve my updates?


Ask yourself this - how does the server even know you exist if you never sent it a message?

Quote:I am trying to stay away from using different ports for the client and the server


This is generally a bad idea. Clients shouldn't bind to any specific port unless the user specifically tells them to (via a command line option or something). If you bind to a specific port you run the risk of port collision (somebody else already has that port), and it's impossible to run two copies of the client on any given box.
-Mike
Quote:Clients shouldn't bind to any specific port unless the user specifically tells them to


I would relax that recommendation. You can bind to a port, if you are prepared that the bind may fail, and are willing to re-try with another port (say, previous port + 1). You should probably re-try at least 10 times before giving up, and reporting the specifics of the problem to the user.

Using a known port or port range makes certain firewall administration scenarios easier.
enum Bool { True, False, FileNotFound };
Thanks very much for the suggestions and recommendations etc. I think I'll go with the idea of the client requesting the update each time. Also I think I have all my problems with UDP mainly resolved now. It's good to get multiple opinions on topics that are as open as this.

I know some people say not to bind, but I find binding the client as a convenience, meaning it can recieve any time it wants, say after it has authenticated with a server. If its bound to an unused port, surely there isn't any real problem to doing this?

Dave

This topic is closed to new replies.

Advertisement