I have a http server to serve so many connections. This server will get data from internet, or from disk, cache to response to client. I want to create some workers to do some job using ZMQ.
ZMQ server will send data to ask worker do their job like insert to db, write to disk and most important send data back to client.
Server :
http.createServer(function(req, res) {
...
zmq_socket_server.send(message);
});
Worker :
zmq_socket.on('message', function(reply) {});
I don't know how to send data from workers to each client request .
Is it possible to do like that or any suggestion ?
You can use a simple request reply pattern using the REQ and RES sockets.
Server:
var socket = zmq.socket('req');
http.createServer(function(req, res) {
socket.send("send data");
socket.on('message',function(reply){
//worker sent back reply
});
});
Client:
var socket = zmq.socket('rep');
socket.on('message', function(data) {
socket.send("reply back here");
});
I have skipped out the obvious socket configuration part where you bind and connect to the socket address in each case, and I am assuming that you are using JustinTulloss's zmq npm module.
Related
This is a pretty simple question but i want to make sure that i am scaling our socket.io implementation correctly. We are using socket.io to respond back to the client after a lengthy process on the nodejs backend. So basically client makes call, then socket.io signals the client that the process has completed. Also socket.io ONLY responds to a temporary room that was established for the request.
In nodejs i created a global variable for the following so that i could emit back to the client room:
global.io = require('socket.io')(server);
But to create the room itself I am a little unsure how to create it globally such that only the socket that connected and made the request receives the response.
So if i have 500 client machines that initiate a connection through socket.io, each one will have its own socket. To ensure that the rooms are unique i use a guid across all 500. Of course i do not want all sockets to receive traffic if only one socket for a specific room is supposed to be evaluating the emit....
any ideas?
If I understood your question correctly, you're looking to send information to that 1 socket?
Perhaps something like this:
socket.broadcast.to(socketId).emit('someeventname', eventData);
If you have the connection open with that client, that means you have their socket id through socket.id . You can emit events to just that socket.
const app = express();
var http = require("http");
var server=http.createServer(app).listen(2525, (req, res) => {
console.log("Server running on", 2525);
});
var socketIO = require("socket.io");
var io = socketIO(server);
global.io = io
io.on("connection", async (socket) => {
socket.on("joinrooms", async (data) => {
socket.join(data.userId);
});
socket.on("sendMessage", async (data) => {
console.log("message", data);
io.to(data.touserId).emit("sendMessage", data);
});
});
/* Must Read section
Joinrrom data sample
data={
userId:123 //User's unique id.
}
sendMessage data sample
data={
userId:123, //sender User's unique id.
touserId:456, //reciver User's unique id.
}
Here I'm creating a room from the user's unique id(stored in DB) so whenever I
want to send data to a particular user I will emit an
event("io.to(data.touserId).emit") using the user's
a unique id that way only specific users will get messages.
*/
The problem I am trying to solve is
client makes a restful POST to node server.
node server communicates with another external server via socket.
when the socket response comes back from the other server - node server responds to client with the data received.
I can communicate to the client via REST and separately I can communicate to the external server via socket (response time is ~100ms). But combining these results yields nothing.
const sjsc = require('sockjs-client');
app.post('/form', function(req, res) {
const srvc = sjsc('http://external.server:port/path');
srvc.onopen = function () {
srvc.send(testData);
}
srvc.onmessage = function(data) {
console.log('received ', data);
res.send(data);
};
});
const srvc = sjsc('http://external.server:port/path');
this needed to be a let. this is the only thing i changed and works perfectly.
let srvc = sjsc('http://external.server:port/path');
I'm building a Pub/Sub Server in NodeJS + Redis + PHP, after dig in on the subject and starting building something I came across some confusion that I saw on the process.
Example Scenario:
5 users are connected to the socket through NodeJscorrectly.
One of them click a button to send an custom alert to all the connected users except him
Php receive the the message for the alert trough a call ajax (for purpose of example)
Php Publish back to Redis
Redis receive the event and trigger socket.io to broadcast the event
Set up view:
<input type="text" id="message">
<button id="sendMessage">Send alert</button>
Client side Js
var socket = io.connect('http://127.0.0.1:3000/');
socket.on('notification', function (data) {
alert(data.message);
console.log('message received');
});
// Ajax event
$(document).on('click','#sendMessage', function(){
$.ajax({
url: '/send/notification',
method: 'POST',
type: 'JSON',
data: { message: $('#message').val() },
success:function(data)
{
console.log('message sent');
}
})
});
Php Server Side for Communicate to redis
$message = $_POST['message'];
$redis = new Predis\Client();
$redis->publish('notification',$message);
NodeJs
At this point on my NodeJs server I will go to listen for the message event in redis for then broadcast the event to sockets but here is the first issue I met.
var http = require('http');
var app = http.createServer();
var io = require('socket.io')(app);
var redis = require('redis');
app.listen(3000,'127.0.0.1',function(){
console.log("listening:", app.address().port, app.address().address);
});
io.on('connection', function(client){
var redisClient = redis.createClient();
redisClient.subscribe('notification');
redisClient.on("message",function(channel,data){
// This line should broadcast to all the client except the sender
socket.broadcast.emit(channel,JSON.parse(data));
console.log(channel);
});
});
Issue
At this point where I console.log() the channel I can see on my terminal 5 logs "notification" Why 5?
When socket.io broadcast the event, it does that 5 times, sending in this case 5 alert() to the clients and 4 to the sender instead of 1 for all clients a 0 for the sender.
The times are depending on how many users are connected I really don't understand what I missed, because it shouldn't be the right behaviour.
I already tried to put the creation of the redisClient and the subscription of a channel outside of the io.on('connection') with no luck, same result.
Another Test
if I broadcast the event on the connection of the socket like so:
io.on('connection', function(client)
{
client.broadcast.emit('notification','hello');
});
It works correctly, so I think is redis problem. Any suggest will be really appreciated.
You are having 5 clients connected, so the "connection" event is fired 5 times.
Thus there are 5 listeners for redis which all then broadcast.
There are two ways to do it correctly:
a) 1 listener per connection, only send the message to the connection
io.on('connection', function(socket){
var redisClient = redis.createClient();
redisClient.subscribe('notification');
redisClient.on("message",function(channel,data){
// This line should broadcast to only the current connection
socket.emit(channel,JSON.parse(data));
console.log(channel);
});
});
b) 1 global listener, broadcast to all clients
var redisClient = redis.createClient();
redisClient.subscribe('notification');
redisClient.on("message",function(channel,data){
// This line should broadcast to all the client except the sender
io.sockets.emit(channel,JSON.parse(data));
console.log(channel);
});
I would prefer method b) as it only needs one redis connection.
I have done same in one project.Only difference is I publish notification from node.js but i did not get any issue.There is broadcast only open socket.
Is it possible to run authentification as soon as socket is connected?
Right now I do this:
io.sockets.on('connection', function (socket) {
socket.on('login', function (token) {
// this is where I currently authtificate users
});
});
If I'm not wrong in this case socket opens on "connection" and hangs there and "login" event may be never called. If someone wants to attack my server, they can simply open thousands of socket connections. How can I authentificate on "connection", I mean right away? So if it fails I will be able to close socket immediately.
Thank you!
It is possible to run authentication when a client tries to connect. Socket.io has a mechanism of authorizing clients when they try to connect to your server, However authorization is disabled by default. There is an object of handshake when a socket tries to connect to server, this object has the request query and request headers etc. You can enforce authorization by this:
io.configure(function (){
io.set('authorization', function (handshakeData, callback) {
if(handshakeData.query.token == "somevalue"){
callback(null, true); // this will allow the client to connect
}else{
callback(null, false); // this will prevent the client from connecting
}
});
});
And on the client side you can send a query string like this:
var socket = io.connect("http://yourIP:Port?token=somevalue");
I need to synchronize some of data immediately between some servers with main one.
So I think the best and easiest way is using WebSocket in NodeJS.I have some experienced with socket.io module,but it provide client to use in browser.I looked at engine.io ,it looks like socket.io too.
Is there any library to make WebSocket connection as client with out browser?
(or any alternative safe protocol for my situation?)
If you're going to be transferring data across servers, you aren't limited to using the HTTP protocol. Instead, you can use raw TCP sockets. This is how you'd make a listen server:
var net = require('net');
var server = net.createServer(function(socket) {
// do what you need
socket.write();
socket.end();
});
server.listen(8080);
And this is how you'd connect to it from another Node process:
var net = require('net');
var client = net.connect({port: 8080}, function() {
// we can send data back
client.write();
});
client.on('data', function(data) {
// receive data here
});
client.on('end', function() {
// we received a FIN packet
});