Multiple Sockets Per Client

Started by
2 comments, last by Dave Weinstein 11 years, 1 month ago

I've been only supporting a TCP socket connection to my server, but now I'd like to add UDP to my architecture. I'd like to use TCP for mission-critical packets, such as when a team scores a point, some one drops in or out of a game, etc, and UDP for things like updating player states. Would this be a good idea? I read on a blog that it's best to use UDP for everything, and try to emulate TCP for those important messages. It stated that having TCP in use would bog my network connection down... This is interesting since I'm sure any device that has Internet connectivity nowadays, whether it's a computer, tablet, or smartphone, it's probably always online transmitting data for an app.

I mean, there's up to 65536 theoretical ports you can which means some one didn't think 255 connections weren't enough back when these protocols were being designed. I've been told that the first 1023 are off-limits because many OSs uses those to provide standard services like mail, FTP, etc. So, that would make sense to me.

Advertisement

You can actually have as many sockets as your OS can support. Sending a message to a public Server is very easy over UDP, you just send a packet there and pray. It is so because you have the IP address of your server. However, sending an UDP packet from the Server back to the Client won't work in the majority of cases, because most users are behind some kind of NAT. There are technique how to "get to" the user called UDP hole punching. It works in a similar fashion like TCP connection. I should mention that it is a bit complicated to implement and is not a common practice (I think).

I think the most straightforward first step of getting some benefits from UDP would be adding Client -> Server "unimportant" event updates. TCP would remain for main connection and the reliable updates, such as the Server game state stream.

For the Server, you can use any port that is not already used. Servers usually are not behind NAT, or ports can be easily forwarded to them. If you are initiating connection over the TCP or only sending data over the UDP you can let the OS to choose your outgoing port, so clients are not bothered by that.

Now, weather it would be a good idea to have UDP: it depends on a game. How many trivial updates do you actually have? For example, in shooters the direction player currently looks at is usually considered as trivial data and it is sent to the server over UDP.

The port numbers are there to identify services. There are more than 255 kinds of services in the world, so 255 port numbers is not enough. (Some argue that 65535 is not enough, and strings should have been used, but it's too late to fix that now :-)

A connection is identified by a four-tuple of (remote IP, remote port, local IP, local port) which means that you can have up to 65535 connections in parallel from one machine to a specific service on another machine. That seems like it should be enough, although remember that TCP connections stay in TIME_WAIT state after being closed for a few minutes, and there actually exists cases where you'll run out! This is mostly for short-lived HTTP requests for service-oriented architecture type systems.

You *can* use a long-lived TCP connection for some messages, and a UDP connection you manage yourself for some other messages. It can work. But, if you're building the UDP part, you might as well put a simple reliability layer on top of that, as long as you don't use that for things like bulk download of large asset files, patches, etc. That will likely actually simplify the messaging/communications code.
enum Bool { True, False, FileNotFound };

Rainbow Six and Rogue Spear used a hybrid TCP/UDP model for networking.

All combat traffic and a reliable movement strobe (1hz for all entities in the game world) went out via TCP. UDP packets handled interstitial movement packets for entities that were determined to be "near" the player.

There are some distinct advantages to this:

1. Writing an efficient ordered/reliable transport layer on top of UDP is not a trivial task.

2. With an ordered/reliable transport layer you get de-facto delta compression on your traffic. Since the key to network game design is knowing what data not to send, and how often to not send it, this is a big win.

3. At the time, a significant percentage of the player base were still on modems. While the UDP header is 28 bytes versus 40 for the TCP header, with header compression (which is supported on TCP but not UDP for historical reasons), that drops down to 5 bytes or so.

You'll note that the key points there were code complexity and bandwidth reduction. All ordered/reliable traffic (TCP or roll-your-own) has a known issue, which is "hitching". If a packet in the middle is lost, you need to hold the later packets which have arrived until the middle packet has been resent.

Later generations of Red Storm games (starting with Ghost Recon 2, if I recall correctly) had everything rolled up into a custom protocol over UDP that handled unreliable, ordered/reliable, and reliable-but-unordered traffic.

The reason had nothing to do with TCP per-se, and everything to do with the change in the consumer environment. By that point in time, a significant percentage of the customer base were behind NAT. It is fairly straightforward (assuming you have a matchmaking service) to bypass NAT over UDP, and impossible to do it with TCP without having the players set up port forwarding for the server.

With all that, my recommendation would be to find a well-tested library that does what you need over a combined reliable/unreliable protocol on top of UDP, and use that. As a general rule, unless you are a very experienced network developer, you should not be implementing your own reliable layer on top of UDP, it is too easy to get wrong.

This topic is closed to new replies.

Advertisement