Multithreaded client and server architecture

After a couple of weeks trying to underestand the samples that comes with Unity Transport, I implemented a basic client and server, but the process left me with some doubts. First, I couldnt find a way to provide the thread with a list of commands to send to the server (like player clicked here, player executed ability, etc). So, I decided that per each iteration of Update() I would send only one command to the network thread. And also, the network thread would read any data incoming from server and provide the main thread only one data packet to process (I really wanted to read all the data coming from server and pass it back to be parsed in Update()). This is my first time with a multiplayer game, so I would like to know if this approach is right or wrong.
The second doubt is that even when such approach is good for client, it doesnt looks so optimal for a multithreaded server. I would like to let the server handle as much client updates per frame as possible, in separated threads. How can I do this?

ConcurrentQueues are useful for moving data between threads for further processing. I’m not understanding what you mean by providing 1 vs all data to the main thread though.

1 Like

Something like this:

main thread:
Update()
complete net thread
check input
put commands (move, execute abilty, etc) in a list
parse/execute incoming server commands (move, etc)
schedule net thread

network thread
send all client commands
read all packets coming from server

My current approach is send one command per frame and process one incoming packet per frame. Im thinking this is not too bad in the client, as probably the player wont manage to click on terrain to move and cast an ability in a single frame and the packets coming from server can wait. But as I said, this is my first time and I may be wrong. Also, doesnt sounds that good in the server side, processing one client request per frame?

I suppose 1 request per frame can work if requests are very infrequent, I’m just not sure why you’d want to do it that way. Processing an individual network message is not a lot of CPU, so it shouldn’t slow your game down to process several messages per frame.

What I do isn’t repeatedly starting and stopping network threads, but just leave the network thread running all the time in a loop. If no work was done on that loop then do a 2ms sleep, otherwise keep running through the loop. By running through the loop I mean reading outgoing messages from the ConcurrentQueue put there on the main thread and sending them out the wire, and reading incoming messages and throwing them on a different ConcurrentQueue for processing back on the main thread.

The main thread then empties the incoming ConcurrentQueue every Update, and throws these incoming messages into various lists for individual channels (I use a channel system, so I can have different settings like encryption, delays waiting for message combining, reliability, etc, per channel). Sorts the lists by message ID (because they can come in out of order with UDP), and then processes them up the chain to wherever the message is supposed to go or whatever the message is supposed to do. I try to process as many of the messages completely on a single Update loop, though there’s some situations where this isn’t possible.

The above seems to work pretty well for me.

Not sure about it, but the Jobs samples stop and start the threads (or jobs) with Complete and Schedule.

Well a job and a thread aren’t really the same thing.

Well, thanks. You made me think, and I was wondering if Jobs were threads.

So a job is some self contained work which the job system will assign to one of its worker threads. When you’re talking about running separate threads though, you’re implying something like System.Threading.Thread instead of the job system. But yeah, what I said above isn’t how you would implement networking with the job system.