Networking, Threads, and Multiplayer

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Networking, Threads, and Multiplayer
by on (#223034)
I've been reading up on both topics lately and was able to make a simple client-server chat program. Now I want to take this idea and extend it to a co-op game with both local and network support. For now, I'm just going to extend my original program to allow for multiple clients to join the server and respond in real time rather than the back and forth messaging it currently has.

If I understand the general concept correctly:

Server
-has 1 thread watching for new and lost connections
-when a user connects, create a new thread with a socket connected to the client
-when a lost connection is found, the main thread will kill that client's thread and remove them from the list of clients

Client
-has 1 thread that just sends and receives messages


Where would the server handle broadcasting messages it receives from one client to the others? The main thread, the thread it received the message from, or would it need a separate thread just for this?

In the case of a game, a person joining would have 2 threads, one for the gameplay and the other for the client (assuming audio/video/simulation was all handled in one thread). Would the host have 3 (main, server, client)?
Re: Networking, Threads, and Multiplayer
by on (#223042)
I have experience in writing full client/server code in C, and handling everything manually. My takeaways when I was done were:



The server I wrote was authoritative, it made it much easier, albeit this will not work well for games. All clients "ask" for what they need to be done. The client then sits on the message until it gets told it's accepted, it applies it locally, and then it queues more messages, or waits for other messages from the server. The downfall is it won't work well for multiplayer games, you would need something that can send and receive states at multiple times away from the last state and apply them accordingly. For this I'd recommend reading up on Valve's multiplayer/game networking they have on their wiki, it's a great read and will show you how they do it and I'd say your best bet is to try to apply what they do, just on a smaller scale. They basically send the full state back and forth, accounting for travel time and where it predicts other players to be, and it works very well as CSGO shows.



Detecting connections dropping is very easy if you don't rely on the OS to do it. If you haven't communicated any data with the server in a few seconds (I used 3 seconds myself) then you send out a keep-alive to it. The server sees the message, and then sends a keep-alive packet back in response. The client never replies to it, only the server. Behind the scenes in the networking code, you're actually resetting a timer on that connection of the last communicated time. The idea for this is to fail out quickly by knowing if you were supposed to get *some* data from *somewhere*. If you don't get a reply, you drop the connection assuming the server never got it, and then try to reconnect after that. The server does the same if it doesn't get your messages. The keep-alive helped not wait for an awfully long timeout that the OS gives the connection. If you're in a multiplayer game, basically, you'll never even need to send the keep-alive packets because you'll always be communicating state information. Only when the server client talking goes low will it need to be sending the keep-alives.



Lastly, to relay the message, the server has to do just that. It has to see it's a chat message and add it to the queue of packets to send to all others.

Client Messages -> Server.

Server->Tells the client it is has accepted the packet or something like that.

Server->Relays to all other clients with the message inside.



Also the program I wrote ran on Raspberry Pi's. You don't have to worry about threads, as long as you don't block on the IO read from the network or something like that, you can write it all in one thread as my program performs fast on even those low powered computers.


If you are writing the code in C on Linux, let me know, I can help you and give you my code that does this. The connection code and socket handling isn't hard and seems like the worst part, but the biggest part of my program was processing the information and applying multiple packet types and state changes from many clients at once and keeping all the clients straight on what their state should be.