I've just developed a nice method for communicating between two different programs on the same Pi.
Benefits
- Performant, uses a RAM drive, is self-cleaning after reboot/restart of either end
- Pipes-like behavior, but a custom set of code to implement it
- Python 3—compatible
- Pairs of pipe files are created after bootup in the RAM drive for
client
&server
- Can respond with
string
or Python objects likedict
(usingmpu.io
) - Assumes client-initiated conversations with optional responses
- Incorporates a mechanism for determining that the other side has read/consumed the message sent
- tcp-like delivery of messages in order and with sequencing
- Works across different programs (doesn't need to be a child process)
- Could also work from a remote computer as well, in theory
- handshake mechanism
- the RAM drive lives under the
/home/pi
subtree and is owned bypi:pi
, making life easy - I think this could be optimized to sub-second roundtrips to the server and back; I've currently set a timeout of two seconds for development purposes
- The naming standard allows messages to easily be processed in the order sent by sorting the directory listing
- Can support multiple services (pipe pairs)
Structure:
-
/home/pi/ramdrive
at bootup -
./ramdrive/servicename/client
andserver
after either end of the communications comes up. -
./servicename/server/YYYYMMDDHHMMSS_1
created withHello\n
as the content; deletion of the file indicates reception and that the communication pipe is in-place -
./servicename/server/YYYYMMDDHHMMSS_2
created by the client withsomeOctoPrintVerb\n
which then results in the server deleting that, creating./client/YYYYMMDDHHMMSS_2.pickle
with a pickled dict object response from OctoPrint from the plugin side of things in this case; the client unpickles the response, deletes the file and has the dict object - essentially, the client creates a new file in
server
and polls theclient
folder for the matched response; the server pollsserver
, runs the report and responds to theclient
folder by creating the match filename
Rationale
I tried rpc
, sockets
, FIFO
s ("named pipes"), couldn't use Queue and other parent/child process sort of solutions... I just kept finding that they wouldn't work at all or wouldn't work well in a fault-tolerant way if both or either end of the communication restarted. The more I worked with them, the more complicated the fault-tolerance code became. So I decided to roll my own on this one.
It behaves like a queue metaphor in that requests are time-stamped, sequenced and consumed. It behaves like rpc
in that binary objects can be shared across programs. It behaves like named pipes in that it includes the service name as part of the path. It includes handshaking, timeouts and pipe-rebuilding after loss of either end.
Blurb
I've created a RAM drive—based named-pipes replacement for inter-process communication to make it easy to separate TFT screen programming, for example, from the OctoPrint plugin interface.