I am working in C#.
I am creating a multiplayer game/chat server.
The game server can run multiple games at a time, with no more than 10 participants in each game.
I intend to only use 1 "game thread" per CPU core, which means a single game thread will run the tick logic for multiple games, then go to sleep until the next tick.
In addition to these game threads, I would like to create a single "network thread" within this multiplayer server that can listen for new TCP connections, incoming TCP data, incoming UDP data, and also receive messages from the game threads which are running tick logic periodically.
The network thread will pass incoming data to the game thread that is dealing with that player endpoint.
It needs to receive messages from the game threads so they can tell it to close a socket for a disconnected player, possibly to send outgoing data through the network thread, and probably other communication I haven't thought of yet.
MSDN says the C# Socket class is thread safe, so perhaps the game threads can send out directly on the sockets, rather than passing their outgoing messages to the network thread to be sent out.
Should I have the game threads pass their outgoing messages to the network thread, or just send them out directly on the sockets?
Game communication is handled over TCP.
I need the incoming UDP data because the game server will also support voice chat between friends (a chat party), linked to a specific game, or linked to a specific team within a game.
I've already got mic capture, encoding to Opus, transmitting via UDP, receiving via UDP, decoding from Opus with its packet loss concealment and forward error correction, and voice sample playback working in a separate test application.
I could send UDP voice data directly between peers, but I don't want to deal with NAT punch through between peers yet, plus it seems like while sending directly between peers could give lower latency, it also has a trade off of sending more upstream data from each client, over the client's possibly podunk network.
The way I usually handle cross thread communication is to use a BlockingCollection which external threads add their messages to, and the receiving thread calls either Take or TryTake, depending on whether it wants to specify a timeout.
For instance, a game thread would call TryTake so it can receive messages from the network thread, but also specify a timeout so it wakes up for the next tick.
For communication where the sender actually wants to block waiting for a result, I group the message with a ManualResetEvent so the sending thread can wait on it until the receiving thread has set the result and triggered it.
I want the network thread to be able to call Socket.Select passing in all its sockets, so it can respond as soon as a new TCP client has connected, or TCP or UDP data is available for reading.
But I also want it to be able to handle messages coming from game threads immediately.
Is there a way to wait on both incoming data from sockets, and incoming messages from other threads?
I currently plan on calling Socket.Select passing in the bound TCP listening socket, the bound UDP socket, and all TCP sockets created by new connections.
For reference, its prototype is:
public static void Select(IList checkRead, IList checkWrite, IList checkError, int microSeconds);
I will pass them in the checkRead parameter, and pass an infinite timeout. (Unless I end up needing to wake up in order to check for messages from other threads.)
It seems like I should also pass them in the checkError parameter, so I can handle connection errors immediately.
Will Socket.Select return when a new UDP packet comes in if I have bound that UDP socket to an EndPoint?
If not, do you have a recommendation for how to wait on both TCP and UDP data at the same time?
Thanks.