I am trying to keep track of all tcp connections that are made in my server and store it in an array.
My problem begins when some connection is closed, in this situation I should delete it from my array but I can't do it. Can anyone help me? How do I delete a socket that is stored in my array?
var net = require("net");
function Server(port) {
var self = this;
this.conections = [];
this.server = net.createServer(function(socket) {
self.conections.push(socket); //storing the socket in the array
})
this.server.listen(port);
console.log("TCP Server created on port: "+ port);
}
module.exports = Server;
After thinking for a while I realized that I could give an ID to each socket, this way I can monitor each new connection in an array and delete it in case the connection is lost.
var net = require("net");
function Server(port) {
var self = this;
this.connections = [];
this.connectionsId = 0;
this.server = net.createServer(function(socket) {
socket.id = self.connectionsId++;
self.connections.push(socket); //storing the socket in the array
})
//Event that is always trigger when the connection is ended
socket.on('close', function() {
self.connections = self.connections.filter(function(conn) {
return conn.id !== socket.id;
});
});
this.server.listen(port);
console.log("TCP Server created on port: "+ port);
}
module.exports = Server;
Hope it helps somebody!
I am having problem in receiving values emitted by socket.io, I am not getting where is the problem. Here am posting the code please help me to solve the problem.
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var bodyParser = require('body-parser');
var path = require('path');
var fs = require('fs');
var spawnSync = require('child_process').spawnSync;
....
app.post('/loadImage',upload.any(),function(req, res) {
fs.readFile('/home/pathtofile/file.json','utf8',function(err,data){
if(err){
console.log(err);
}else{
//console.log(data);
var precjson = JSON.parse(data);
var loaded_filename = precjson.Filename;
io.emit('emitfilename',{loaded_filename});
}
})
}
http.listen(8080,'0.0.0.0',function(){
console.log('listening on 8080');
})
And here is my code where I am receiving the emitted values:
<script type="text/javascript">
var socket = io.connect('http://localhost:8080');
socket.on('emitfilename',function(data){
//console.log(data);
var li = document.createElement('li');
var filename = document.createElement('h4');
filename.textContent = 'File Name:' + data.filename;
li.appendChild(filename);
document.getElementById('filenameoutput').appendChild(li);
});
</script>
Instead of getting file name , I am getting undefined. Can any one please help me.
You can't use "io" variable to emit data. You can use current socket of the client that just connected to send data :
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Or use io.sockets to emit to all sockets
io.sockets.emit('users_count', clients);
Hope it solve your problem ! Thanks !
I'm fairly new to node.js and recently started to make some modules. However I've come to a point where communication between modules is required. Since this is not a problem I've encountered in the past I'm stuck with finding a clean solution.
This is the boilerplate I currently got (Left out some checks to make the code a bit smaller). The basic idea atm is joining any irc channel given by an http post.
bot.js
//Include services
var Webservice = require('./Webservice');
var Ircservice = require('./Ircservice');
//Create service instances
var webservice = new Webservice();
var ircservice = new Ircservice();
//Initialize services
webservice.init(1337);
ircservice.init('alt-irc.snoonet.org', 80, 'User');
//Handle events
ircservice.on('irc-registered', function(msg){
console.log(ircservice.connected);
ircservice.joinChannel('#testchannel')
});
ircservice.on('irc-join', function(channel){
console.log('Successfuly joined: ' + channel);
});
webservice.on('web-join', function(streamer){
ircservice.joinChannel('#' + streamer);
});
Webservice.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
app.use(bodyParser.urlencoded({
extended: true
}));
var Webservice = function(){
EventEmitter.call(this);
};
Webservice.prototype.init = function(port){
app.listen(port, function () {
console.log('Webserver listening on ' + port);
});
this.initRoutes();
};
Webservice.prototype.initRoutes = function(){
var self = this;
//join a irc-channel
app.post('/join', function (req, res) {
var streamer = req.body.name;
self.emit('web-join', streamer);
res.send('Received')
});
};
util.inherits(Webservice, EventEmitter);
module.exports = Webservice;
Ircservice.js
var irc = require('irc');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var Ircservice = function(){
EventEmitter.call(this);
}
Ircservice.prototype.init = function(server, port, nick){
this.client = new irc.Client(server, nick, {
port: parseInt(port)
});
this.initListerners();
};
Ircservice.prototype.initListerners = function(){
var self = this;
this.client.addListener('message', function (from, to, message) {
console.log(from + ' => ' + to + ': ' + message);
});
this.client.addListener('join', function(channel, nick, message){
self.emit('irc-join', channel);
});
};
Ircservice.prototype.joinChannel = function(channel){
this.client.join(channel, null);
};
util.inherits(Ircservice, EventEmitter);
module.exports = Ircservice;
This example works perfectly, but as you can see the communication between my webservice and ircservice is handled by the bot.js. While this is perfectly fine for this example, I cannot use this method whenever I want.
Let say in the future I want to keep a list in my ircservice of all channels he has joined and display this through a webpage. I could keep a local array on my ircservice and on the join event add that channel to the array. But how do I continue on the webservice end. I can write an endpoint '/getchannels' but my webservice itself is not aware of the ircserver to get the channels (ircservice.getChannels or something similar) and firing an event in my web request doesn't feel like the way to go.
One solution that came up in my mind was passing the instances of the services to each other like webservice.setIrcservice(ircservice) and the other way around in the bot.js. But this feels like dirty code and a hard depency.
So how can I communicate between modules when I need data instantaneously and events are no option?
i have one doubt regarding socket.io.I have two type of user i.e-admin,client .First admin will create userid and join to the room.I need when user will join room the admin should get response and need help regarding this.
My working codes are given below.
server.js:
var port=8888;
var express=require('express');
var morgan = require('morgan');
var http=require('http');
var bodyParser= require('body-parser');
var methodOverride = require('method-override');
var mongo = require('mongojs');
var database='Oditek';
var collections=['video'];
var app= express();
var server=http.Server(app);
var io=require('socket.io')(server);
var db = mongo.connect("127.0.0.1:27017/"+database, collections);
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded
app.use(bodyParser.json()) // parse application/json
app.use(methodOverride()); // simulate DELETE and PUT
db.on('ready', function () {
console.log('database connected')
});
app.get('/',function(req,res){
res.sendfile('view/login.html');
});
app.post('/login',function(req,res){
var username=req.body.username;
var password=req.body.userpassword;
if(username && password){
db.video.findOne({
username:username,
password:password
},function(err,doc){
if(doc){
console.log('login',doc);
res.send(doc);
}
if(err){
console.log('login12',err);
res.send("could not login");
}
});
}
});
app.get('/video',function(req,res){
res.sendfile('view/video.html');
});
//socket----programming//
var roomid;
io.on('connection',function(socket){
//console.log(socket);
roomid=socket.handshake.query.roomid;
var usertype=socket.handshake.query.usertype;
socket.join(roomid);
});
server.listen(port);
console.log('server is listening on the port'+port);
My client side code is given below.
function videoBroadCasting(uType){
var messageGateWay;
if(uType=='admin'){
var userid = getRandomString();
$('#styled').val('http://localhost:8888/video?usertype=client & id='+userid);
messageGateWay=io('http://localhost:8888/?roomid='+userid+'usertype='+uType);
}
if(uType=='user'){
messageGateWay=io('http://localhost:8888/?usertype='+uType);
}
messageGateWay.on('connect',function(){
console.log('socket get connected');
});
}
function getRandomString() {
return (Math.random() * new Date().getTime()).toString(36).replace(/\./g, '');
}
function getQuery(key){
var temp = location.search.match(new RegExp(key + "=(.*?)($|\&)", "i"));
if(!temp) return;
return temp[1];
}
After client is joining the room the admin should get one notification.Please help me to do this.
One simple solution is to save the socket object from the admin in the server when the admin joins the room. Then, when some other user join the room, simply emit a message to that socket from the admin/admins. Just keep an array update with the admins actually logged in the room.
Something like:
var socketAdmin = {};
io.on('adminJoins',function(socket){
socketAdmin = socket;
roomid=socket.handshake.query.roomid;
var usertype=socket.handshake.query.usertype;
socket.join(roomid);
});
io.on('clientJoins',function(socket){
roomid=socket.handshake.query.roomid;
socketAdmin.emit('newClient', {socketClient: socket, roomId: roomid};
var usertype=socket.handshake.query.usertype;
socket.join(roomid);
});
In this example, the client sends a message 'adminJoins' if you are an admin, or 'clientJoins' ir you are a client, you can send that checking the uType var you have. In case a new client joins the room, the admin recieve a 'newClient' message with the socket of the client and the roomId (just an example).
I'm making a chat app with socket.io, and I'd like to use my custom client id, instead of the default ones (8411473621394412707, 1120516437992682114). Is there any ways of sending the custom identifier when connecting or just using something to track a custom name for each ID? Thanks!
You can create an array on the server, and store custom objects on it. For example, you could store the id created by Socket.io and a custom ID sent by each client to the server:
var util = require("util"),
io = require('/socket.io').listen(8080),
fs = require('fs'),
os = require('os'),
url = require('url');
var clients =[];
io.sockets.on('connection', function (socket) {
socket.on('storeClientInfo', function (data) {
var clientInfo = new Object();
clientInfo.customId = data.customId;
clientInfo.clientId = socket.id;
clients.push(clientInfo);
});
socket.on('disconnect', function (data) {
for( var i=0, len=clients.length; i<len; ++i ){
var c = clients[i];
if(c.clientId == socket.id){
clients.splice(i,1);
break;
}
}
});
});
in this example, you need to call storeClientInfo from each client.
<script>
var socket = io.connect('http://localhost', {port: 8080});
socket.on('connect', function (data) {
socket.emit('storeClientInfo', { customId:"000CustomIdHere0000" });
});
</script>
Hope this helps.
To set custom socket id, generateId function must be overwritten. Both of eio and engine props of Socket.io server object can be used for to manage this operation.
A simple example:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
io.engine.generateId = function (req) {
// generate a new custom id here
return 1
}
io.on('connection', function (socket) {
console.log(socket.id); // writes 1 on the console
})
It seems to be it has been handled.
It must be in mind that socket id must be unpredictable and unique value with considering security and the app operations!
Extra: If socket.id is returned as undefined because of your intense processes on your generateId method, async/await combination can be used to overcome this issue on node.js version 7.6.0 and later. handshake method of node_modules/engine.io/lib/server.js file should be changed as following:
current:
// engine.io/lib/server.js
Server.prototype.generateId = function (req) {
return base64id.generateId();
};
Server.prototype.handshake = function (transportName, req) {
var id = this.generateId(req);
...
}
new:
// function assignment
io.engine.generateId = function (req) {
return new Promise(function (resolve, reject) {
let id;
// some intense id generation processes
// ...
resolve(id);
});
};
// engine.io/lib/server.js
Server.prototype.handshake = async function (transportName, req) {
var id = await this.generateId(req);
...
}
Note: At Engine.io v4.0, generateId method would accept a callback. So it would not needed to change handshake method. Only generateId method replacement is going to be enough. For instance:
io.engine.generateId = function (req, callback) {
// some intense id generation processes
// ...
callback(id);
};
In the newest socket.io (version 1.x) you can do something like this
socket = io.connect('http://localhost');
socket.on('connect', function() {
console.log(socket.io.engine.id); // old ID
socket.io.engine.id = 'new ID';
console.log(socket.io.engine.id); // new ID
});
I would use an object as a hash lookup - this will save you looping through an array
var clients = {};
clients[customId] = clientId;
var lookup = clients[customId];
Do not change the socket IDs to ones of your own choosing, it breaks the Socket.io room system entirely. It will fail silently and you'll have no clue why your clients aren't receiving the messages.
This will work with 2.2.0 and above version of Socket.IO
To set custom Socket Id, generateId function must be overwritten.
A simple example:
Server Side
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
io.use((socket, next) => {
io.engine.generateId = () => {
// USE ONE OF THESE
socket.handshake.query.CustomId; // this work for me
// return socket.handshake.query.CustomId;
}
next(null, true);
});
io.on('connection', function (socket) {
console.log(socket.id);
})
Clint Side
io.connect(URL, { query: "CustomId = CUSTOM ID IS HERE" })
NOTE: Keep in mind that socket id must be a unique value.
why not a simpler solution that does not need to maintain an array of connected clients and does not override internal socket id?
io.on("connection", (socket) => {
socket.on('storeClientInfo', (data) => {
console.log("connected custom id:", data.customId);
socket.customId = data.customId;
});
socket.on("disconnect", () => {
console.log("disconnected custom id:", socket.customId);
})
});
Client side
let customId = "your_custom_device_id";
socket.on("connect", () => {
socket.emit('storeClientInfo', { customId: customId });
});
or you can override the socket id, like this:
io.on('connection', function(socket){
socket.id = "YOUR_CUSTOM_ID";
});
you can see under the array:
io.sockets.sockets
Can store customId (example userId) in object format instead of for loop, this will improve performance during connection, disconnect and retrieving socketId for emitting
`
var userId_SocketId_KeyPair = {};
var socketId_UserId_KeyPair = {};
_io.on('connection', (socket) => {
console.log('Client connected');
//On socket disconnect
socket.on('disconnect', () => {
// Removing sockets
let socketId = socket.id;
let userId = socketId_UserId_KeyPair[socketId];
delete socketId_UserId_KeyPair[socketId];
if (userId != undefined) {
delete userId_SocketId_KeyPair[userId];
}
console.log("onDisconnect deleted socket with userId :" + "\nUserId,socketId :" + userId + "," + socketId);
});
//Store client info
socket.on('storeClientInfo', function (data) {
let jsonObject = JSON.parse(data);
let userId = jsonObject.userId;
let socketId = socket.id;
userId_SocketId_KeyPair[userId] = socketId;
socketId_UserId_KeyPair[socketId] = userId;
console.log("storeClientInfo called with :" + data + "\nUserId,socketId :" + userId + "," + socketId);
});
`
With this 2.2.0 version of Socket.IO, you can achieve this.
io.use((socket, next) => {
io.engine.generateId = () => socket.handshake.query.token;
next(null, true);
});
If you are trying to use a custom id to in order to communicate with a specific client then you can do this
io.on('connection', function(socket){
socket.id = "someId"
io.sockets.connected["someId"] = io.sockets.connected[socket.id];
// them emit to it by id like this
io.sockets.connected["someId"].emit("some message", "message content")
});