I've been trying to learn how to handle network input in C++ (using asio for networking). Right now I'm trying to build a program which should be able to receive commands and data from a client through the network which it should handle in different ways, but I'm stuck when it comes to how this can be done in a nice decoupled way.
For example, a simple program which will receive compressed images through a TCP connection (or in my case UDP, but that shouldn't make a big difference for my question) and render them on a screen, might have these classes for Networking:
- NetworkServer (listens and receives connections on new threads)
- ConnectionManager (keeps track of connections)
- Connection (handles a session)
And for decompressing and displaying images on the screen, these classes:
- Decompressor (handles decompressing images)
- Screen (handles a the screen, can take a raw bitmap and display it)
And then we have a Server class which is started in main, and holds the Screen, Decompressor, and the NetworkServer which it also starts.
So let's say a Connection starts receiving a compressed image at >1mb that's been separated into many smaller chunks (1kb each?) which's data should be forwarded to a Decompressor, which in turn will forward the complete image to the Screen once the full image has been decompressed.
For this scenario, how is the data supposed to flow from the Connection to the Decompressor? I'd assume that it's bad design to have each Connection handle a reference to a Decompressor (because what if we also want the server to control audio, video, a chat and lights through TCP connections, should each connection have references to all of those?).
I was thinking something along the lines of having the connection push the binary messages received into a queue, and having a separate class MessageDeliverer running on a different thread parse the messages (into a class called ImageChunkMessage or so?) and forward them to where they should be handled. Is this a good solution even if the messages can contain quite a bit of data? I'd assume it'd be good practice to let the Decompressor "subscribe" to messages relevant to it (again, if we add audio then maybe a class controlling the audio playback/decompression would subscribe to "AudioChunkMessages"). However, this would mean that the Decompressor class has be able to handle ImageChunkMessages, and that doesn't feel like good design? (it'd be nicer of the message part would be parsed somewhere else, and the Compressor is called directly with the data from the message, but where should this parsing happen?)
I hope that was understandable enough. This is just an example I came up with while writing this post so it's obviously very simplified (and most likely has plenty of flaws), but hopefully it's good enough to explain the question I have.
Are there any good "standard" ways for handling this that aren't language/framework specific? It feels like there should be plenty of articles covering this, but either I'm searching for the wrong thing or there's not as much as I'd have thought. I've tried looking at some open source projects, but it'd take me weeks to understand their flow since they're quite big.