I have an application that I'm writing that needs to be able to update all connected clients whenever a client connects to a local socket server via an ajax request and updates the system. handling the request is fine but sending the response from the local socket server to socket.io to broadcast to everyone is where I'm having an issue. I'm sure it's something simple I'm looking over here but this is very new to me so I'm having problems, specifically with the asynchronous programming mindset. Below is a shortened version of what I'm trying to accomplish and where I'm faltering.
var express = require('express'),
http = require('http'),
net = require('net'),
app = express(),
server = http.createServer(app),
io = require('socket.io').listen(server);
app.get("/execute", function (req, res) {
// connect to local socket server
var localSock = net.createConnection("10000","127.0.0.1");
localSock.setEncoding('utf8');
localSock.on('data', function(data) {
// send returned results from local socket server to all clients
do stuff here to data ...
send data to all connected clients view socketio socket...
var dataToSend = data;
localSock.end();
}).on('connect', function(data) {
// send GET data to local socket server to execute
var command = req.query["command"];
localSock.write(command);
});
app.get (..., function() {});
app.get (..., function() {});
server.listen('3000');
io.on('connection', function(client) {
client.broadcast.send(dataToSend);
});
The global socket object is referenced as io.sockets. Therefore, to globally broadcast, just pass data to io.sockets.emit() and it will be send to all clients, regardless of namespace.
The code that you posted, assuming you meant io.sockets.on:
io.on('connection', function(client) {
client.broadcast.send(dataToSend);
});
Is listening for any connection to any namespace, and broadcasting dataToSend to all clients once a connection has been established. Since your main objective is to send data to everyone, you would just leverage the global namespace, io.sockets, but the way it is used in your code doesn't work.
app.get('/execute', function (req, res) {
var localSock = net.createConnection("10000","127.0.0.1");
localSock.setEncoding('utf8');
localSock.on('connect', function(data) {
var command = req.query.command;
localSock.write(command);
});
localSock.on('data', function(data) {
var dataToSend = data;
localSock.end();
});
});
In this part of your code, you are properly listening for GET requests on the path /execute but your socket logic isn't correct. You are writing command immediately on connection, which is fine, but you are assuming that the data event means that the stream of data has ended. Since the stream has the event end, you would want to collect the response with the data events, then finally do something with the data on end;
For example, if the server sent the string This is a string that is being streamed. and you were to use:
localSock.on('data', function(data) {
var dataToSend = data;
localSock.end();
});
You might only receive This is a stri and then prematurely close the socket with end(). Instead, you would want to do this:
var dataToSend = [];
localSock.on('data', function(data) {
dataToSend.push(data);
});
localSock.on('end', function() {
dataToSend = dataToSend.join('');
io.sockets.emit(dataToSend);
});
Note that in this case, you don't need to use end() because the remove server will send its own FIN packet.
I'd like to ask what you're doing with net.Socket, because the data returned is a Readable Stream, which means, when you listen on the data event, the data may be fragments of the full response that have to be collected until the end event is fired. If what you're trying to do is send a message to a socket.io server, then you could instead use socket.io-client, socket.io's own client.
Here is some code from a very popular webtutorial. Some changes were made in order to use Express 3.x.
here is the code of app.js:
var express = require('express')
, http = require('http');
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
server.listen(8000);
// routing
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
// usernames which are currently connected to the chat
var usernames = {};
io.sockets.on('connection', function (socket) {
// when the client emits 'sendchat', this listens and executes
socket.on('sendchat', function (data) {
// we tell the client to execute 'updatechat' with 2 parameters
io.sockets.emit('updatechat', socket.username, data);
});
// when the client emits 'adduser', this listens and executes
socket.on('adduser', function(username){
// we store the username in the socket session for this client
socket.username = username;
// add the client's username to the global list
usernames[username] = username;
// echo to client they've connected
socket.emit('updatechat', 'SERVER', 'you have connected');
// echo globally (all clients) that a person has connected
socket.broadcast.emit('updatechat', 'SERVER', username + ' has connected');
// update the list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
});
// when the user disconnects.. perform this
socket.on('disconnect', function(){
// remove the username from global usernames list
delete usernames[socket.username];
// update list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
// echo globally that this client has left
socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has disconnected');
});
});
The obove code is the same code as in the webtutorial only some changes for Express 3.x were made using the answer of Riwels .
here is the code of index.html:
<script src="/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script>
var socket = io.connect('http://localhost:8000');
// on connection to server, ask for user's name with an anonymous callback
socket.on('connect', function(){
// call the server-side function 'adduser' and send one parameter (value of prompt)
socket.emit('adduser', prompt("What's your name?"));
});
// listener, whenever the server emits 'updatechat', this updates the chat body
socket.on('updatechat', function (username, data) {
$('#conversation').append('<b>'+username + ':</b> ' + data + '<br>');
});
// listener, whenever the server emits 'updateusers', this updates the username list
socket.on('updateusers', function(data) {
$('#users').empty();
$.each(data, function(key, value) {
$('#users').append('<div>' + key + '</div>');
});
});
// on load of page
$(function(){
// when the client clicks SEND
$('#datasend').click( function() {
var message = $('#data').val();
$('#data').val('');
// tell server to execute 'sendchat' and send along one parameter
socket.emit('sendchat', message);
});
// when the client hits ENTER on their keyboard
$('#data').keypress(function(e) {
if(e.which == 13) {
$(this).blur();
$('#datasend').focus().click();
}
});
});
</script>
<div style="float:left;width:100px;border-right:1px solid black;height:300px;padding:10px;overflow:scroll-y;">
<b>USERS</b>
<div id="users"></div>
</div>
<div style="float:left;width:300px;height:250px;overflow:scroll-y;padding:10px;">
<div id="conversation"></div>
<input id="data" style="width:200px;" />
<input type="button" id="datasend" value="send" />
</div>