I'm making a game with network multiplayer that will be playable with crossplay from multiple platforms. The game is written in c++ and uses regular TCP sockets for network communication. Currently the game exists on windows but ideally it will exist on ios/android/linux/mac as well. The server is a single process written to run on Ubuntu Linux. Currently, clients find the server by hard coded url which is resolved to the server IP, and a hard coded port.
This is fine as long as the clients/server are developed/shipped in perfect lockstep. If I change the client or network code in some way, I have the power to just release the client update and start running the new server version simultaneously.
The problem is that once I've released on multiple platforms, I'll never be able to ship an update to all clients at once. Additionally, old versions of the client will exist in the wild forever.
If I add a version handshake to the beginning of each connection, I could detect and deactivate multiplayer features in old clients. With this constraint, I could only operate one server for all platforms (big upside).
Delayed updates would cause a version of the game to be broken temporarily (for example the App Store could reject an update unexpectedly). If my App Store build falls behind, it would not be supported by the current server.
What simple methods exist for supporting multiple api versions when your server is a single process communicating over TCP?
What are the typical solutions to this problem? I know games like Hearthstone achieve this but I assume they have some massive server infrastructure/ops team to help with this.