This is an experiment that I started after using many different message queues in the projects I have worked. This is not production ready code. Please do not rely on it!
The architecture and the protocols of this library will evolve over time. For now, we just support inproc, however when I start to work on the next protocols (IPC and socket), it will need to evolve.
There are many excellent brokerless message queue systems and some of them even provide a zero-copy message passing interface (for inproc data transfer anyway) and you should be using one of them instead:
However, these are not the simplest solution possible and also requires some background I/O and sometimes other nonsense reaper threads.
If you want some really simple and lightweight event-driven framework, check (QP/C)[https://github.com/QuantumLeaps/qpc].
In QNQ, we can have background threads if the implementation of some protocol requires it. But for many cases, they are not necessary and should not be on by default.
Another big difference in QNQ is that we prefer to pass the messages as pointers. For processes communicating in the same machine or with high performance network interfaces, we like to just create the data in place, before it is copied.
So for in intra-host communication, the threads can communicate inside a process
by just passing the pointers around, and using a pipe(2) to manage the
signalling and access to the queue. For IPC, we will use Unix Domain Sockets or
posix MQ just for signalling, but the actual data is passed using shared memory.
This is specially useful when we need to stream video or other multimedia data that requires high performance networking where memory copying will be harmful.
TODO: write about the name
Check the demo or the test directories.
For now, the lib only works in POSIX systems such as Linux or NuttX.
The information is exchanged in messages. Sometimes it will need to be serialized and passed as a stream (eg. TCP or Unix Domain sockets).
There is no such thing as a half-message or some parts of it. You either get the full message, or you don't get it.
There is a standard interface provided to the application, no matter if the other endpoint of the communication is on the same process or over the network.
The interface provided to the application is just a simple zero-copy read/write, which uses a file descriptor (pipe) for signalling. So it will be simple to write an application that uses poll for managing multiple endpoints.
A zero-copy mechanism is used whenever is possible. In case of the inproc
transport protocol, the data is passed just as a pointer (along some metadata).
This can be a pointer to anything, data in the heap, stack, constant, another
structure that the use can signal the lifecycle of the object. anything.
A listener is just an endpoint bound to an URL. This URL is the only place where you specify the endpoint listener you are connecting to. It can be something in the current thread, process, another process in the same machine or another process in a remote machine.
For now, we only support inproc, so communication between threads on the same process.
As with nng and ZeroMQ, we will support multiple scalability protocols for req/rep, pub/sub, etc. However I just implemented the simplest one which is the pair. It provides bidirectional coomunication between two endpoints.
The library will provide simple functions to allocate and free all the data
structures in the heap (using malloc(3)), but will also provide functions to
just initialize the structures using user provided buffers.
This allows a fine tuned control of how and where the data and the structures are stored (heap, statically linked, stack, etc).
We shall consume as little resources as possible, and let the user configure all the possible buffers and policies for the protocols.
For now, only the inproc transport protocol is supported, but we will add more in the future:
-
inproc -
uds+shm -
posixmq+shm -
posixmq -
uds -
tcp -
ws -
quic -
tcp+tls -
wss
We can even add more higher level transports:
- mqtt
- zeromq/nanomsg/sp1
- NATS
This is the simplest transport protocol as for zero copy we just need to pass pointers around. Thread syncronization is difficult in these systems, so we just abstract away the locking and polling from the user.
For passing data around, all the lib does it manage a queue for each endpoint
and signal it using poll(2) and pipe(2) file descriptors.
This protocol also provides an in-process directory that binds names to listener
endpoints. This allows us to specify urls with names (inproc://hello) to bind
and find the endpoints to start the connection handshake.
TODO
TODO
TODO
TODO