TCP comm architecture advice request
-
Hi all,
I need to make a simple communication between a PC and a SBC (Raspberry Pi) using the TCP protocol.
- The user "front-end" is the PC, where I'm developing a small program based on the QSystemTrayIcon - this uses DHCP.
- The "back-end" is the Raspberry Pi which acquires some data that writes to a file - this uses static IP.
Here my requirements:
- When something happens the back-end records data to the disk and and then it must notify the front-end.
- The front-end receives these notifications and must be able to show the available data present in the back-end.
- If for any reason the communication drops, it must be possible to reconnect without restart the applications.
- Both applications developed on Python.
My first attempt I made:
- Front-end as client using QTcpSocket
- Back-end as server.
This design was sensible to me as the client could always know the server IP, but in case of communication drop I couldn't restart the communication. It was based on thread and I couldn't find a way to stop and start the server thread.
To solve the above and to meet my requirements I thought to do the follow:
- Front-end as server using QTcpServer:
- This could easily accept any new connection coming from the back-end, as the QAbstractSocket uses the callbacks (slots/signals).
- I would eventually use a 1 second alive a message to monitor the communication state between the client and the server.
Can you help me with the following questions?
- How the client (back-end) would know to which IP connect as the server is configured as DHCP?
- Is it a good idea use a kind of alive message to check the communication status?
- The server will easily receive message based on the readyRead signal. Does the client needs to implement another thread to manage the recv method (and avoid to be blocked)?
Any other suggestion is more than welcomed!
Kind regards,
AGA -
You should take a look at the Threaded Fortune Server and Fortune Client example projects, they provide most of the building blocks you need to get started. There are plenty of other network-coding examples besides those, it's a whole category in the Qt Creator "Examples" section.
Addressing some specific things you brought up...
@superaga said in TCP comm architecture advice request:
This design was sensible to me as the client could always know the server IP, but in case of communication drop I couldn't restart the communication. It was based on thread and I couldn't find a way to stop and start the server thread.
Correct, it is sensible, and if you were stuck on reestablishing the connection you should solve that problem (it is completely solvable), not totally upend your design in favor of something else that's not sensible.
To solve the above and to meet my requirements I thought to do the follow:
Front-end as server using QTcpServer:
This could easily accept any new connection coming from the back-end, as the QAbstractSocket uses the callbacks (slots/signals).?? Then why can't the backend use QTcpServer to accept any new connection coming from the client? (It can.) If you've solved the problem in one direction you've solved it in the other direction.
But whenever you start saying backwards things like,
Front-end as server
It's usually a sign you're going down a wrong path.
There are valid protocol designs which invert the traditional client-server model. One common example are remote-display technologies like X11 or PipeWire, where GUI applications execute on remote systems and display locally. (As opposed to remote-desktop protocols like VNC and RDP, where you connect to a GUI rendered on the remote system.) When a remote application outputs to the local display, technically the client (local) system is providing a display server, for which the remote application is a client. ....But situations where it's necessary and appropriate to break the model like that are uncommon, and there has to be a really good reason for it. You tend to know when you're in one of those.
You are not.
Before you go any farther into the coding of this system, I'd recommend getting a really firm handle on the design of the client-server communication model. It's important to have a good handle on the role(s) each part plays and what their responsibilities are. When you've got that well-defined, writing the code to make it work becomes a lot easier.
Your concerns about DHCP are valid and correct. Even more damning would be NAT, which makes it impossible to establish an incoming connection without setting up port mappings in the NAT router. It's why servers DON'T connect to clients. Clients connect to servers. (Even in the remote-display case, the machine running the display server is still the client, and it establishes the connection to the remote system that executes the remote-display client.)
A server's job is to make itself available to receive connections, to service those connections, and to manage state for the various clients it serves. Full stop.
The client's job is to connect to the server, establish its identity in whatever ways are required for the server to handle its requests, and communicate with the server until such time as all of its tasks have been completed, at which point it disconnects.
If the client is prematurely or unexpectedly disconnected, it's the client's job to reestablish the connection so that it can resume communication.
The server's job, in case of an unexpected loss of communication, is to be ready to receive a new connection from the client so that their communication can resume. That may require recording some data about the state of the connection at the time it was lost, to facilitate picking back up from that point in the interaction. But it's never the server's job to worry about reestablishing communication with the client.
(That's especially true in modern networking environments, where it's entirely possible that the reason a client dropped communication is that it switched networks — imagine a cell phone going out of WiFi range and switching to 5G, for example. In that type of situation, it's literally impossible for the server to contact the client, because the client's IP address has changed and the server has no way of determining its new IP.)
Don't invert your network simply because it might seem a bit easier to code it that way. Trust me, it's not. In fact it'll create insurmountable obstacles you just haven't run into yet.
-
Hi @FeRDNYC many thanks for your great message!
This is what I was looking for... and this is why I wrote here. I completely agree with you on all.I felt that there was something "stinky" in the design, that's why I asked for some advices... At least some considerations were right.
I always strive to follow the best practice, but sometimes it is quite hard find some clues about it, so many thanks for your time 😉.Regarding this point:
@FeRDNYC said in TCP comm architecture advice request:?? Then why can't the backend use QTcpServer to accept any new connection coming from the client? (It can.) If you've solved the problem in one direction you've solved it in the other direction.
I'm running without the X-server so PyQt/PySide didn't work and I didn't want to install the graphic environement just to make the code run (I felt that would have been a bad workaround - as I couldn't understand why it didn't work). More over as I didn't need to make any interface I thought that would have been wrong use qt just because was simple... I wanted to use something because it was right.
Ok, then I'll go through the example you suggested me to understand the "network communication design".
-
@superaga said in TCP comm architecture advice request:
I'm running without the X-server so PyQt/PySide didn't work and I didn't want to install the graphic environement
There is no need to install graphic environment to run PyQt/PySide console applications. Just make sure your application as a proper console application (for example use https://doc.qt.io/qt-6/qcoreapplication.html).
-
@superaga said in TCP comm architecture advice request:
I'm running without the X-server so PyQt/PySide didn't work and I didn't want to install the graphic environement just to make the code run
Was about to say the same as @jsulm but he was faster :)
You don't need any GUI to run aQTcpServer
since it's part of the Qt Networking module and no QtGUI or QtWidgets stuff is really needed. -
S superaga has marked this topic as solved on