简体   繁体   中英

PUB/SUB Api doesn't send messages back, what might be the problem?

I have almost completed pub/sub fake-server, that requests user password and email (from the client), compares this info with database and returns data back. It has 'api_in' and 'api_out' frames and then the JSON. The publisher takes and processes all the info without a hitch, but it doesn't seem to send anything back to the client (subscriber) and I don't know why, cause it is connected to the subsequent port.

And I know that this implementation is not a classic PUB/SUB pattern, but that was prerequisite, to do it like that.

I tried different pub/sub options, but nothing has changed.

Server

let zmq = require('zeromq');
const sqlite3 = require('sqlite3').verbose();

const DBSOURCE = "./db.sqlite";

let db  = new sqlite3.Database(DBSOURCE, (err) => {
    if(err) {
        console.error(err.message);
        throw err;
    } else {
        console.log('Connected to SQLite database');
        db.run(`CREATE TABLE users (
        user_id INTEGER, 
        email TEXT,
        passw TEXT)`,
            (err) => {
                if (err) {
                    // Table already created
                } else {
                    // Creating rows
                    let insert = 'INSERT INTO users (user_id, email, passw) VALUES (?,?,?)';
                    db.run(insert, [123098, 'phillCollins@gmail.com','5502013']);
                    db.run(insert, [42424242,'dukenukem3d@mustdie.com','RodriguesShallLiveLong']);
                    db.run(insert, [5,'yourchick@yandex.ru','semolinaAndPain666']);

                }
            })
    }
});


const args = require('minimist')(process.argv.slice(2));

const pubSocket = zmq.socket('pub', null);

pubSocket.bindSync(`tcp://127.0.0.1:${args['pub']}`);

const subSocket = zmq.socket('sub', null);

subSocket.subscribe('api_in');

subSocket.on('message', function(data) {
    let message = data.toString().replace(/api_in/g, '');
    let mes = JSON.parse(message);

    let api_out = 'api_out';

    let errorWrongPWD = 'WRONG_PWD';
    let errorWrongFormat = 'WRONG_FORMAT';

    if(mes.type = 'login') {
        db.get(`SELECT user_id from users WHERE email = ? and passw = ?`, [mes.email, mes.pwd], function(err, row) {
            if(err) {
                console.log(err);
            } else {
                if(row) {
                    let msg = {
                        msg_id: mes.msg_id,
                        user_id: row.user_id,
                        status: 'ok'
                    }

                    let outMessage = api_out + JSON.stringify(msg);

                    console.log(outMessage);
                    subSocket.send(outMessage);
                } else {
                    let msg = {
                        msg_id: mes.msg_id,
                        status: 'error',
                        error: mes.email == '' || mes.pwd == '' ?  errorWrongFormat : errorWrongPWD
                    }
                    console.log(msg);

                    let outMessage = api_out + JSON.stringify(msg);

                    subSocket.send(outMessage);
                }
            }
        });
    }
});


subSocket.bindSync(`tcp://127.0.0.1:${args['sub']}`);

client

let zmq = require('zeromq');
let uniqid = require('uniqid');

let readline = require('readline').createInterface({
    input: process.stdin,
    output: process.stdout
});

const args = require('minimist')(process.argv.slice(2));

const pubSocket = zmq.socket('pub', null);

let pubSocketTCP = `tcp://127.0.0.1:${args['sub']}`;

pubSocket.connect(pubSocketTCP);

const subSocket = zmq.socket('sub', null);

let subSocketTCP = `tcp://127.0.0.1:${args['pub']}`;

subSocket.connect(subSocketTCP);



let api_in = 'api_in';
let secondFrame = {
    type: 'login',
    email: '',
    pwd: '',
    msg_id: uniqid()
}

readline.question('What is your email? \n', (email) => {
    secondFrame.email = email;
    readline.question('What is your password \n', (pwd) => {
        secondFrame.pwd = pwd;
        let msg = api_in + JSON.stringify(secondFrame);
        console.log(msg);
        pubSocket.send(msg);
    });
});

subSocket.subscribe('api_out');

subSocket.on('message', (response) => {
/*     let res = response.toString().replace('api_out');
    let responseParsed = JSON.parse(res);
    console.log(responseParsed.status);
    if(response.status == 'error') console.log(response.error); */
    console.log(response);
}); 

I want the server side to send info back.

Your server is trying to send on the sub socket

subSocket.send(outMessage);

You can't send on the sub socket. It should be sending on a pub socket.

Well, first of all, welcome to the Zen-of-Zero domain. ZeroMQ is a powerful tool for smart signaling / messaging, so if you pay attention to all its internal beauties, there will be no such thing you will not be able to do with it ( nightmares still not avoided on this way forward ). If feeling to be new to this domain, one may enjoy a short read into "ZeroMQ Principles in less than Five Seconds " before diving into further details on subject, or re-use some of tricks posted here

Q : it doesn't seem to send anything back to the client (subscriber) and I don't know why

There are two pieces of code, that seem to use both PUB and SUB Scalable Formal Communication Pattern Archetypes, yet have some glitches on how these get configured.


The server-code :

seems to try to instantiate PUB -archetype and equips that instance with a single AccessPoint, using .bindSync() -method and cli-parameter args['pub'] for accepting connections over a plain and common tcp:// -transport-class.

After defining the event-handler .on( 'message', ... ) for the second instance, being the SUB -archetype, this one becomes .bindSync() -equipped with a single AccessPoint, using tcp:// -transport-class, for receiving connections using tcp:// -transport-class.

If you indeed have to make a .send() over a SUB -alike archetype, you have to use XSUB alternative, where you can send data and perform some tricks with the actual payload on the PUB -side or XPUB -side ( ref. API documentation for details about ZMQ_XPUB_MANUAL mode capabilities and limits for some wilder data-mangling on the XPUB -side )

ZMQ_XSUB

Same as ZMQ_SUB except that you subscribe by sending subscription messages to the socket. Subscription message is a byte 1 (for subscriptions) or byte 0 (for unsubscriptions) followed by the subscription body. Messages without a sub/unsub prefix may also be sent, but have no effect on subscription status.


The client-code :

Seems to instantiate and .connect() both the client-local PUB and SUB Archetypes over tcp:// -transport-class to the server-side AccessPoints ( which both ought to set ZMQ_LINGER to 0, so as to avoid infinitely hanging orphans ( version dependent defaults do not have other solution but an explicit setting on this ) ).


Possible improvements :

  • XPUB/XSUB with ZMQ_XPUB_MANUAL may solve the sending via SUB -archetype
  • XPUB/SUB with ZMQ_XPUB_MANUAL may solve the sending via SUB -archetype with less comfort of masquerading the messages to be sent via the .subscribe() -method
  • PUB/SUB with making all .send() -s strictly via a local PUB -archetype instance.
  • be explicit with ZMQ_SNDHWM and ZMQ_RCVHWM parameters if still loosing messages
  • be explicit on setting .subscribe() only after a successfully completed { .bind() + .connect() } -methods ( systematically using original zmq_errno() and zmq_strerror() functions for actively detecting and repairing the potential colliding states )
  • may request to work with only completed connections ( distributed systems have zero-warranty of an order of operations autonomous distributed (many) agents perform ) using .setsockopt( ZMQ_IMMEDIATE, 1 )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM