Nio - seperating types of incomming data

What I’m trying to accomplish:
A multiplayer spacesim for about 20-50 players, with in-game chat. Dedicated server program. For now assume I do it all with TCP.

Questions:
Should I make more then one socketchannel for each client? Like chat messages go on channel1, positiondata goes on channel2, otherstuff on channel3, etc…
Or is it better to seperate chat and gamedata by starting each message with an ID. (Like if the first byte is a 1, treat it as a chatmessage, if it’s a 2, treat it as a positionmessage etc…)
Is there a 3rd (better) option?

If the answer is only use 1 socketchannel per player, then what use is a selector on the client side? I can understand the use of a selector on the serverside, cause it manages multiple clients, but on the client side it seems needlessly complicated to use one.

I’ve also read about splitting read and write operations on seperate selectors. Is this a good idea? cause it seems to me it further complicates things.

I would like some advice on the best networking design for my goal please :slight_smile:

With 50 connections there is no reason to resort to (the can of worms named) NIO.

Just make 50 threads, that push data on a queue, and let 1 thread process all incoming/outgoing data.

Option 2 is what I use for all networking things I do. The first byte determines what type of packet it is and it sent to the appropriate handler.

A lot of folks here hate NIO, I don’t really know why. It works fine and i don’t really think it is that hard to use. It works as advertised and i had a full working single threaded n socket capable network manager in a day. I can scale threads and connection per thread.

On clients you don’t need to use a selector… you can use a single socket. Of course you can use one thread per connection on the server as well, at least on linux this is even faster than selectors. But now you have many threads not just one or two with the required synchronization, which can be its own can of worms. Also on windows it grinds to halt after a few 100 threads on xp anyway and is generally slower than selectors.

At 50 connections either method would work. I would still use a selector on the server so i have one network thread (read and write) to sync up with the rest of the program.

As for delimiting messages on your stream, i just use message delimiters like you say. Since some messages can be different lengths, my first field is the length in bytes. If i get out of sync, I “reset” the connection.

Ok I decided to ditch NIO and go back to IO.

Question:
Cause this socket IO is blocking, wouldn’t I need 2 threads per socket? One for reading and one for writing? That would make 100 threads instead of 50.

I have 1 thread for each connection that receives commands (reads) and replies to them (writes).

No you dont, only the reader needs a thread.
You send messages with methodcall à la

writer = new PrintWriter(socket.getOutputStream());

public void sendMsg(String msg){
writer.println(msg);
writer.flush;
}

Yes, he does . If the sending of the message blocks for any reason, your game will also freeze until the message is sent . Though it may be rare to block the sending message, I have learned in the last years that if something has a chance to happen, it WILL happen . Never neglect a rare case .

It is possible to use just one Thread. It is actually the way I’m doing right now .
First I check if there are bytes to be read. If yes, I parse them and send them to a queue for processing by the game later.
Else, I check if there are messages queued to be sent.
Else , I sleep a little and repeat again .
The code : (try catch have been removed for the sake of readability):


DataInputStream inFromClient; 
....

	while(active)
		{ 
				if (inFromClient.available()>0)
				  {
				  readDataFromClientAndInsertInParsersQueue(); 
				  }
				else  if (!sendMessageQueue.isEmpty())
				{
					sendQueuedMessages();						 
				}
                                else
                                {
                                Thread.sleep(sleepTime);
                                }
            
		}  

I can’t tell you if this is an excellent approach but it has been working for me .
Any comments from the specialists ?

Well wait a minute, I didn’t know that was possible! (The available check)

This is my version of your suggestion:

	 
out = new PrintWriter(game.network.socket.getOutputStream(), true);
InputStream is = socket.getInputStream();
in = new BufferedReader(new InputStreamReader(is));
String chatMsg = "";
    		
while (true) {
   if (in.ready()) {
      game.gameGui.addMsg(in.readLine());
   }
    			
   if ((chatMsg = game.network.chatQueueOut.poll()) != null) {
      out.println(chatMsg);
   }
    			
   Thread.sleep(1);
}

(Also removed try-catches for readability)

Doesn’t this effectively make the reading part non-blocking?
It appears to work but like you said, I would like some feedback from others too :slight_smile:

The available call is one way to do non blocking stream IO. You are now just using stream non blocking to mux the read/write rather than a selector. Nothing wrong with that.

However I have only done non blocking writes with selectors. When i am doing the streams i have never needed non blocking writes except with network code, where there is either a thread or a selector.