Many applications need to communicate using messages instead of streams. This is present on nanomsg and zeromq. I was wondering why libuv does not support this.
As I have not found a lightweight solution (no websockets, just 4 bytes length-prefixed message framing) I developed one and released under MIT license here:
https://github.com/litesync/libuv_message_framing
I am trying to make the implementation the more similar to libuv ABI as possible.
So if you think it can be integrated in libuv in the future, it would be ready.
You are free to make comments on the implementation. We can change it while it is in Draft Proposal.
What do you think about a lightweight Message-based Communication on libuv? (it can be another solution, not mine)
What do you think about the solution I am implementing?
You are building an ad-hoc custom protocol on top of TCP, which is fine, but why would it get adopted by libuv? The world is full of protocols, they can be implemented on top of uv, like yours is.
If you like implementing protocols, perhaps read http://www.rfc-editor.org/rfc/rfc3117.txt
When we use nanomsg and zeromq we don't need to implement our own protocol. Message-based communication is there ready to be used.
So why not also in libuv?
Note that this implementation does not force others to use it. The stream interface is still there and we can also implement other message-based protocols. But it is useful to have at least a simple and lightweight one already available.
And the integration does not need to be done now. We'll just wait and check if there is demand for this.
If there is no demand for integration, it can be used on top of libuv.
So if you have suggestions on its implementation, they are welcome.
Many applications need to communicate using messages instead of streams. This is present on nanomsg and zeromq. I was wondering why libuv does not support this.
Because libuv is a cross-platform i/o abstraction library, it doesn't (and won't) implement application layer protocols. libuv provides applications with the transport capabilities, in the form of streams (TCP, pipes and TTY) and UDP, and it's completely up to them to implement a protocol on top.
The fact that your example is completely self-contained (which is a great thing!) further strengthens the point of not neededing it inside libuv :-)
Feel free to add you rproject to the projects list on the wiki but it has no place inside libuv.
OK. If it can be completely self-contained it is good indeed.
But I was not able to implement the handle closing. Can someone give me some tips to improve it?
Where is the best place to store private data for the application layer protocol?
I thougth about these 2 options:
use stream->data
extend the uv_tcp_t, like this:
struct uv_msg_s {
uv_tcp_t tcp;
MSG_PRIVATE_FIELDS
};
As I want to support so TCP as pipes, the first part of the struct would have enough
space so for uv_tcp_t as for uv_pipe_t. So we can use a union, like this:
struct uv_msg_s {
union {
uv_tcp_t tcp;
uv_pipe_t pipe;
};
MSG_PRIVATE_FIELDS
};
But I want the user to access the data field too, so we can add it to the union, as it is the first field from handle:
struct uv_msg_s {
union {
uv_tcp_t tcp;
uv_pipe_t pipe;
void *data;
};
MSG_PRIVATE_FIELDS
};
So the user can access it like this:
uv_msg_t msg;
msg->data = ...
This works at least with C11 (unnamed union).
So the option 1 as option 2 appear to work. The problem is when closing the handle.
There is a buffer in the private fields that must be released when the handle is closed.
But when uv_close is called by the user app libuv will call the user supplied callback, not mine.
I see that uv_close uses the handle->type to call the appropriate close function. But it will not call the one for uv_msg.
Workaround:
I implemented a way in which the buffer is always released on a read completion.
For this to work I only need the guarantee that uv_read_cb is called with nread < 0 when the uv_close is called on a stream in which the read was not completed.
Or is there a more elegant way?
I realized that uv_read_cb is not fired when uv_close is called.
More info here:
uv_close does not cause invocation of uv_read_cb?
So, how to release the resources in the case libuv calls alloc_cb but not uv_read_cb?
Can this happen?
If this does not happen, then it is done!
If alloc_cb is ever called, read_cb will be called.
Thank you!
Most helpful comment
Because libuv is a cross-platform i/o abstraction library, it doesn't (and won't) implement application layer protocols. libuv provides applications with the transport capabilities, in the form of streams (TCP, pipes and TTY) and UDP, and it's completely up to them to implement a protocol on top.
The fact that your example is completely self-contained (which is a great thing!) further strengthens the point of not neededing it inside libuv :-)
Feel free to add you rproject to the projects list on the wiki but it has no place inside libuv.