Handling both UDP and TCP input. Multithreading?

So, after over a month of work on the networking for my game, I am nearly done (2k+ lines of code later :)) with networking for a while! It now comes down to one thing: how to manage both TCP and UDP input to the client/server at the same time. I can send and receive UDP and TCP packets just fine, but the process of reading TCP and UDP is where I run into an issue. Both methods for receiving packets are blocking, meaning it stops the entire thread until it received a packet. I already have three threads for each player connection (main connection thread, packet-input thread, packet-output thread). If I try to have both packets being read for in the one packet-input thread, whichever type is read for first blocks the thread from reading for the next type of packet (UDP first means TCP won’t be received until UDP packet is read first, and vice versa). The simplest solution would be to split the packet-input thread into a TCP-input and UDP-input thread, but I’d want to avoid this if possible. I am sure there are other ways out there, I just don’t know them. How should I approach this?

Here’s my current (non-functioning properly) reading code. This code is just for testing purposes, not the complete code :stuck_out_tongue:


//Elsewhere...
DataInputStream input;

try
{
	byte[] udpData = new byte[26];
	byte[] tcpData = new byte[26];

	DatagramPacket udpPacket = new DatagramPacket(udpData, udpData.length);
				
	base.getDatagramSocket().receive(udpPacket);

	//TCP Packet can't be received unless a  UDP Packet is received. After first UDP-
	//-packet is received, a TCP must be received before receiving another UDP, and so on.
	tcpData = new byte[input.available()];
	input.read(tcpData);

         Packet udpPacket = Packet.extractPacketFromData(udpData);
         Packet tcpPacket = Packet.extractPacketFromData(udpData);
}

Don’t use blocking IO; use non-blocking Channels along with a Selector.

So I’ve started on restructuring my entire server/client system to work with NIO instead of IO, but I’m having an issue. Whenever a client connects to the server, the server throws a BindException when trying to bind a UDP port to listen to for client UDP packets. Both the client and server are trying to use the same port, which I believe is the cause, but isn’t that how it’s supposed to be done? Or is it possibly an issue with the code itself?

Relevant Server code:


			// Server stuff above blah blah blah

			ServerSocketChannel serverSocketChannel;
			serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.bind(new InetSocketAddress(9090);
			serverSocketChannel.configureBlocking(true);

			//Elsewhere...

			SocketChannel tcpChannel;
			tcpChannel = serverSocketChannel.accept();
			
			DatagramChannel udpChannel;
			
			udpChannel = DatagramChannel.open();
			udpChannel.bind(new InetSocketAddress(((InetSocketAddress)(tcpChannel.getRemoteAddress())).getAddress(), 9091)); //THROWS BindException: Address already in use
			udpChannel.configureBlocking(false);

			// Server stuff below blah blah blah

Relevant Client code:


				SocketChannel socket;
				socket = SocketChannel.open();
				socket.connect(new InetSocketAddress(ServerManager.SERVER_IP, 9090));
				
				tcpChannel = socket;
				tcpChannel.configureBlocking(false);
				
				udpChannel = DatagramChannel.open();
				udpChannel.bind(new InetSocketAddress(((InetSocketAddress)(tcpChannel.getRemoteAddress())).getAddress(), 9091)); //Binds to address of server
				udpChannel.configureBlocking(false);

In both cases:
TCP Port = 9090 (SocketChannel does fine with this, no issues)
UDP Port = 9091 (DatagramChannel causes the issue with the BindException)

Client is connecting to the server from localhost

On a side note: I tried to cut the code down to only the relevant stuff. Sorry if it’s a little long. :confused:

No, you need to use different ports for the server and the client. So, I would recommend having the server’s port fixed and the client’s port can be anything, you don’t have to worry about it.


socket = new DatagramSocket(port);


socket = new DatagramSocket();

The client will automatically assign a random available port to the client.

Make a thread for the server and one for the client, you should be fine.

The Thread Loop:


public void run() {
		running = true;
		while (running) {
			byte[] data = new byte[1024];
			DatagramPacket packet = new DatagramPacket(data, data.length);
			try {
				socket.receive(packet);
			} catch (IOException e) {
				e.printStackTrace();
			}

			processPacket(packet);
		}
	}

So you can have this in the server and client threads.

I hope I have solved your problem :smiley:

You can try to activate SO_REUSEADDR (http://docs.oracle.com/javase/7/docs/api/java/net/StandardSocketOptions.html#SO_REUSEADDR) on both SocketChannels but it depends on the OS it works or not.

It should be just as simple to just use a thread-per-client model with blocking IO… you might want to give your reasons for the advice.

Cas :slight_smile:

My suggestion was responding to this request by the OP.

[quote]The simplest solution would be to split the packet-input thread into a TCP-input and UDP-input thread, but I’d want to avoid this if possible.
[/quote]
If he doesn’t want blocking, and doesn’t want lots of threads, non-blocking Channels accessed through a Selector is the logical suggestion.

Hm that’s true but I wonder if the OP is actually seeing problems where none actually exist. One thread each per TCP and UDP connection is small beans if there’s less than a hundred clients, say. More importantly we might wonder why the mixture of TCP and UDP in the first place, as the two rarely coexist nicely.

Cas :slight_smile:

I don’t see an issue with it per se, I simply thought it was recommended against. For every connection I would have 4 threads if I used a thread for TCP and another for UDP. I’d have a main connection thread, TCP input thread, UDP input thread, and an output thread. Assuming I have 25 connected clients, that’d be 100 threads for connections alone. Seems inefficient to me. Would you guys recommend I just go with Java’s normal IO and multi-thread TCP and UDP?

While you’re just getting stuff to work… I’d go for normal IO, and not use UDP at all. That’d leave you with one main server accept-thread, and then two threads per client.

If you must use UDP, you can handle all UDP traffic from all clients on one thread. You might find thought that if you’ve got any significant communication over both protocols at the same time though that one or both of them will suffer unexpectedly a lot.

Cas :slight_smile:

With it being the kind of game it is, UDP and TCP combined are almost required. For example, sending login info should be TCP. That NEEDS to be correct and received. Entity location, however, would be UDP. If you missed the packets on the entity location, you won’t need to retrieve the old packet with the old location. You’ll need the new packet with the actual location. (Heartbeat packets being another example).

So long as you’re not generally trying to do lots of both simultaneously, as I understand it, that will probably work out OK.

Cas :slight_smile:

Some time ago I read a paper about udp vs tcp and why a lot of people think they need udp but they would be just fine with tcp. Unluckily I can’t find atm …
TCP isn’t that slow at all. Indeed using TCP and some smart interpolation between steps is fine in most cases. Of course UDP is usefull and sometimes required but implementing udp and tcp for a game that isn’t finished and you don’t know if you will get performance problems is quite time-wasting.
I always prefer easy readable code and structures. I don’t care about performance until I get some issues :slight_smile:
Replacing some slow TCP messages with UDP should be easy in the end.
If you want to learn how to use udp and tcp at once that approach is fine but the hardest part in game-development is getting something playable.

Like always, that is just my point of view ;D

How can TCP be slower than UDP? Are the packets somehow traveling at a different speed? :stuck_out_tongue:

TCP is just as fast as UDP, it’s just that there will be hickups with TCP when packets get dropped, triggering a resend, causing all packets that do arrive to queue up, awaiting the replacement for the dropped packet.

Whether this is relevant, depends a lot on the nominal latency between peers. With a 5ms latency the re-send will be swift, while with a 500ms latency the re-send will be noticable.

TL;DR: start out with TCP, get it to work - that’s hard enough.

Surely 1 packet out is “faster” than 1 out and 1 in + whatever is dropped.

I mean unless you have a fast pace game in which milliseconds can make big differences, TCP will suffice of course.

It’s not about speed, it’s about latency and bandwidth.

When disregarding packet delivery/ordering, it’s not a clear case either:
TCP is faster: it is more efficient with bandwidth, so your download is bound to be done sooner.
UDP is faster: as doesn’t suffer so much from ‘hickups’, getting you your little packets of data faster.

Much of this discussion can be dropped, if the OP explains his interpretation of ‘faster’ for us.

As to make this reply not entirely offtopic…

If you have a request/response setup, you only need 1 thread per TCP-connection.
However you build it, you only need 1 thread for UDP per application.

So, with ‘normal I/O’, with 100 clients, you’d probably have 101 threads handling them.

I can’t find where I would have said TCP is faster than UDP. I don’t know enough about either protocol to even have a stance on the matter, so perhaps you guys misinterpreted something I said somewhere. As for one UDP thread per application, I have no idea how this would be done or how it works. If I have one UDP thread, how would I send UDP packets to a client without holding up that entire thread? Also, how would I determine where the packet came from, so as to send a packet to that client in response?

I don’t think TCP is faster than UDP as long as you don’t care about packet-loss. The ip should be written in the header. I am not sure if you also get the port.
After all you shouldn’t care about performance if you don’t run into problems :slight_smile:

@Phibedy please reread topic, that is not what op is talking about

And here lies your problem, shadowstryker.

You maintain some connection between IP addresses and users, then handle the packets in the order you receive them, responding to the proper client. There is no “holding up the entire thread”. Most of the time for packets to send is network latency, which doesn’t affect how quickly you can move on to the next packet.

Try doing some more testing or even learn a little more about UDP vs TCP (ie. how you send data on each, because it’s very different), and you’ll quickly see what the other posters mean when they suggest one UDP thread per application.