Converting from TCP to UDP - Threading Clients?

After many headaches, I have decided it is in my best interest to convert my client/server game to UDP from TCP. I am not interested in starting any TCP vs UDP discussion in this thread.

Currently, the setup is as follows (simplified)

Client

  • Attempts connection to server. If success…
    • Creates a thread to listen for messages from server.
    • Processes client input, sends messages from server, interprets server response.

Server

  • Waits for connection attempts. If a connection happens …
    • Create a thread to listen for messages from client.
  • Processes server input, sends messages to client, interprets client messages.

Pretty much the same on both sides except that there will be multiple threads generated by the server, one for each client.

I am having a fairly difficult time finding useful UDP examples to reference. I was using http://systembash.com/content/a-simple-java-udp-server-and-udp-client/ as a reference, but one main concern comes to mind.

Right now, when the server gets an incoming connection from a client, I create a new Socket for that client and pass it to the listen thread. With this UDP example, it seems to just accept any traffic over a given port … so all of my traffic would go towards a single DatagramSocket.receive running on the main server. I guess I can get the IP address from the message in order to determine what player it belongs to but it really makes the whole thread part useless if all the messages will come to the same exact place. Am I correct in thinking this way?

Possible UDP setup?:

Client

  • Attempt to communicate with server. If successful…
    • Creates a thread to listen for messages from server.
    • Processes client input, sends messages from server, interprets server response.

Server

  • Create Main listen thread
    • Main Listen thread gets ALL messages from ALL clients. As soon as a message comes in, it determines which client it belongs to and hands the message off to a client-specific thread (or creates one if this is the client’s first time connecting)
      • Client Listen thread processes the message and passes the response back to the client.
  • Processes server input, sends messages to client, interprets client messages.

Yep, you are.

Well you could do this yourself this way but i think youre in better shape by using a Networking-lib. I think nettys udp works (for the programmer) almost the same way as tcp since netty creates “fake”-connections and handles the delegating (to which session/connection this packet belongs) itself.

Thanks for the reply. I’ll have to look up this “Nettys”, I’m sure there’s a few threads around here.

This is exactly how you should do this, I see you have already digged into this stuff (which is why I reply).
You should ignore tkausl’s suggestion because I see no reason why you shouldn’t do this yourself, if you want to keep it fast and organized at least…

Here is how I did it in my previous game:

	public Runnable receiver = new Runnable(){
		byte[] receiveData = new byte[1024];
		int id = 0; // until we have connection to database use this temporary!!!!
		
		public void run(){
			while(running){
				total:
				try {
					DatagramPacket datagramPacket = new DatagramPacket(receiveData, receiveData.length);
					server.receive(datagramPacket);
					for(Client c : clients){
						if(c.dp.getSocketAddress().equals(datagramPacket.getSocketAddress())){
							c.handleMsg(datagramPacket.getData());
							break total;
						}
					}
					clients.add(new Client(datagramPacket, id++));
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
			server.close();
		}
	};

I also have very nice code which handles the packet loss and eventual delivers them in order (and in incredibly quick :slight_smile: ), if you would like to have them, you know where to find me.

Hi Herjan,

I actually tried implementing this last night (manually, not with Nettys) and it looks incredibly similar to what you posted above. So far my trouble is in converting the object I’ve been using for TCP network messages to a byte[] to use in UDP network transfer. I’m still playing with it and it’s rather messy. I feel like I’m passing data around much more in this setup. Do you keep the send and receive code for UDP in the same place?

As far as packet loss, I think I’d like to take a thwack at that myself before looking for help. Looks like it might be kinda fun :slight_smile:

Thanks,
Chumble

Haha, that’s the spirit! And heck you will learn a lot thanks to that spirit :smiley:

And about the sending of packets, actually, in the same class, I had this function:

public void write(DatagramPacket dp, int pckg, String[] parts) {
		String msg = "" + pckg;
		for(int i = 0; i < parts.length; i++)
			msg += PackageHandler.separator + parts[i];
		
		msg += PackageHandler.endPackage;
		dp.setData(msg.getBytes());
		
		try {
			sender.send(dp);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

int pckg, tells the server/client what to do with this data:

  • a login
  • input
  • or whatever

Ok, so I think I have the basics pretty well set up. It works with multiple clients locally. However, when I switch over to my external IP address to test it with a friend, the server gets the “Connection” request but the client never gets a response. This comes down to port forwarding, I believe.

On my router, I have forwarded the port that is used for the server when setting up the socket.
Server: socket = new DatagramSocket(54532);

On the client, I don’t have anything forwarded… I just have a port obtained automatically
Client: socket = new DatagramSocket();

So it appears to me that the client sends data to the server (me) via port 54532 and since it’s forwarded, it works fine. But when the server replies to the client (getting the port with a Packet.getPort() ), the client doesn’t get it. I feel like if I happened to have that port forwarded, it would work fine… but I also feel like I shouldn’t have to.

In my experience with online games, I’ve only had to forward ports when I am hosting a server, never when joining a game. I guess this comes down to a lack of understanding on how the networking works… but it also might be bad code.

Do I need to establish a specific port for the client to listen to the server? If so, will I need it to be forwarded (and, less importantly, why)? And finally, will this prevent me from running multiple clients on MY pc since it will attempt to bind the same port multiple times?

The answer: No, you should not.

If the client doesn’t receive any messages, it’s because you are doing something wrong in the server or (probably) client, you are probably using more than one datagramsocket in your client? (which you should not)

I am not. I make sure that “New DatagramSocket” only appears in the client once and in the server once.