Thursday, 25 May 2017

Node & V8 Engine: Managing multiple socket clients especially with recv and send operations

I made a NodeJS addon which creates a socket connection on a specific port:

V8/C++ code:

void Connect(const Nan::FunctionCallbackInfo<v8::Value>& args) {
    // bind, connect, here
    // processed an event emitter from JS,
    // assign an id to it and return it thru a callback
    while(1) {
        usleep(2000000);
        printf("Emitting from %s", buffer); // buffer here is an id I assigned for this socket
        Local<Value> messageEvent[2] = { String::NewFromUtf8(isolate, "message"), String::NewFromUtf8(isolate, "Hello!") };
        Local<Function> emit = Local<Function>::Cast(rawSocket->Object::Get(String::NewFromUtf8(isolate, "emit")));
        emit->::Function::Call(rawSocket, 2, messageEvent);
     }
}

So this basically connects me to a specific set of addresses, which also returns an event emitter which I assigned an ID to. The event emitter will be the representation of the socket when I get back to JS. Here I was to simulate the recv operation with emitting message events every 2 seconds.

on the JS part:

const rawSocket = new Events.EventEmitter();

Addon.Connect(rawSocket, ["iptobind"],["iptoconnect"], some-port, (err, socket) => {
    if (err) {
        console.log(err);
        return;
    }
    console.log("Socket ID: ", socket.ID);

    socket.on('message', (data) => {
        console.log("data from " + socket.id + ": " + data);
    });
});

This JS code snippet works and message event is being triggered from the C++ side every 2 seconds.

Now I want to create another socket connecting with a different port.

What I tried so far is this:

const rawSocket = new Events.EventEmitter();

Addon.Connect(rawSocket, ["iptobind"],["iptoconnect"], some-port, (err, socketA) => {
    if (err) {
        console.log(err);
        return;
    }
    console.log("Socket ID: ", socketA.ID);

    socketA.on('message', (data) => {
        console.log("data from " + socketA.id + ": " + data);
    });

    const anotherRawSocket = new Events.EventEmitter();

    Addon.Connect(rawSocket, ["iptobind"],["iptoconnect"], another-port, (err, socketB) => {
    if (err) {
        console.log(err);
        return;
    }
    console.log("Socket ID: ", socketB.ID);

    socketB.on('message', (data) => {
        console.log("data from " + socketB.id + ": " + data);
    });

});

I renamed the passed socket with socketA and socketB. I also called Connect again inside the callback of socketA.

Now, the log result is this. Say the socket ID of socketA is 10:

Socket ID:  10 // Socket A created
Socket ID:  11 // Socket B created
Emitting from 11 data from 11: Hello!
Emitting from 11 data from 11: Hello!
Emitting from 11 data from 11: Hello!
Emitting from 11 data from 11: Hello!
Emitting from 11 data from 11: Hello!

For some reason the first while loop from socketA won't emit the message event anymore. But I suspect it was not suspended either because I still can see it sending heartbeats in my wireshark captures.

I've read about using Persistent Handles and utilizing Isolates and Context but I haven't tried to a full extent. I'm thinking of placing the recv operation in that while loop and creating another C++ function template for sending messages.

My question is how can I create multiple clients with this setup as well as how can I manage the connections properly?

Any help will be greatly appreciated. Thanks. :)



via Phenelo

No comments:

Post a Comment