1

My scenario is as follows: I'm using a high-level C++ binding for 0MQ zmqpp.

I have a publisher socket (XPUB), to which multiple subscribers connect(XSUB). The subscription message starts a cascade of events in my application (that's why I use XPUB). I want to pass some extra information as a part of the subscription message, though I don't want it to be the part of subscription topic, so I put this extra information in the second frame of the message (it can't be sent as a separate message for race-condition reasons). Sadly (or not...) the minute the XPUB socket sees the subscription byte (0x01), it takes for granted that this message can only have one frame and splits it (at least I think this is the reason for such behavior). So the second frame comes as another message.

I though of reading both of these messages and restoring the original 2-frame message either by simply reading them one by one, or by using the receive_raw() function of the socket. My only fear is, that for some reason, the two frames of the original message shall be interleaved with messages from the other clients, working concurrently. I use a poll-in poller with zmqpp::reactor on the XPUB socket to receive the messages and forward them to the internal components, single threaded.

So, my questions is: do my fears have some basis or they are baseless?

This is the code that causes the behavior:

#include <zmqpp/zmqpp.hpp>
#include <iostream>

int main(int argc, char **argv)
{
    using namespace zmqpp;
    using namespace std;

    char frame1[] = {1, 's', 'u', 'b', 's', '\0'};
    char frame2[] = {'d','a','t','a', '\0'};

    context_t context;

    socket_t xpubSocket(context, socket_type::xpub);
    xpubSocket.bind("inproc://pub");

    socket_t xsubSocket(context, socket_type::xsub);
    xsubSocket.connect("inproc://pub");

    xsubSocket.send_raw(frame1, strlen(frame1), socket_t::send_more);
    xsubSocket.send_raw(frame2, strlen(frame2));

    //I changed the first byte to be non-subscription
    char frame1_1[] = {3, 's', 'u', 'b', 's', '\0'};    
    xsubSocket.send_raw(frame1_1, strlen(frame1), socket_t::send_more);
    xsubSocket.send_raw(frame2, strlen(frame2));

    bool doContinue = true;
    while(doContinue)
    {
        message_t incoming;
        doContinue = xpubSocket.receive(incoming, true);

        if(!doContinue)
        {
            break;
        }
        cout << endl <<"New Message: " << endl;

        for(size_t i = 0 ; i < incoming.parts() ; ++i)
        {
            cout << "Frame: " << i << "\t" << incoming.get(i) << endl;
        }
    }
}

The output is:

New Message: 
Frame: 0    subs

New Message: 
Frame: 0    data

New Message: 
Frame: 0    subs
Frame: 1    data

So, it looks like whenever the XPUB socket sees a subscription byte on, it assumes the message has only one frame.

I'm running this on ubuntu, here are package versions:

dpkg -l | grep zmq
ii  libzmq3:i386                                          4.0.4+dfsg-2                                        i386         lightweight messaging kernel (shared library)
ii  libzmq3-dev:i386                                      4.0.4+dfsg-2                                        i386         lightweight messaging kernel (development files)
ii  libzmqpp-dev:i386                                     3.2.0-0ubuntu3                                      i386         High-level C++ bindings for zeromq3 - development files
ii  libzmqpp3:i386                                        3.2.0-0ubuntu3                                      i386         High-level C++ bindings for zeromq3
Kikosha
  • 343
  • 6
  • 16
  • 1
    What you're describing, a multi-frame message being broken up into multiple messages, doesn't sound right. Show some code, we may be able to figure out why that's happening. – Jason Jun 24 '15 at 22:56
  • I added the use case to the question – Kikosha Jun 25 '15 at 10:57
  • 1
    What happens in your example if you simplify everything, use strings instead of character arrays, use `send()` instead of `send_raw()`? What happens if you switch the order in which you send your messages, using `frame1_1` first, and then `frame1`? – Jason Jun 25 '15 at 14:14
  • I tried both of your suggestions, precisely the same result – Kikosha Jun 26 '15 at 07:35
  • 1
    When you say the same result, do you mean that it splits the first message frames into two messages and the second message comes as one message in two frames, or do you mean that the one with `frame1` gets split into two messages and `frame1_1` comes as one message? – Jason Jun 26 '15 at 13:37
  • Also, I wasn't clear when I said using strings, but you should be able to omit the null bytes at the end of your strings, just in case you still put them in there. – Jason Jun 26 '15 at 13:41
  • What I means was that frame1_1 still came as one message with two frames and frame1 get split. The null byte didn't influence the result – Kikosha Jun 27 '15 at 10:49
  • Without any more info, sounds like a bug in your binding. I'd take it to their [issues page](https://github.com/zeromq/zmqpp/issues) and see if they can give you any guidance. – Jason Jun 29 '15 at 13:23

0 Answers0