I'm trying to use socket.io to have a client send a message to the server and then the server then sends some info back. Here's what my code looks like
Server Side
let app = express();
let server = app.listen(3000);
app.use(express.static('public'));
let socket = require('socket.io');
let io = socket(server);
let playerData = [[],[],[],[],[]];
io.sockets.on('connection', (socket) => {
console.log(socket.id);
socket.on("joinRoom",(data) =>{
socket.join(data.room);
console.log("recieved join request by socket: " + socket.id + " " + data.class);
let intRoom = parseInt(data.room) // parses what room to join (from string to int)
socket.to(data.room).emit('newJoin', {id: socket.id, class: data.class}); // Tells room that a new user has joined
socket.emit("success", "You have succesfully joined a lobby");
socket.emit('addPlayers', playerData[intRoom]) // Sends player the data of all other players in the room
playerData[intRoom]
playerData[intRoom].push(data.player);
})
})
Client Side
if(enteringRoom){
// This if statement is being run every frame
if(player.loaded){
console.log('telling server to join room'); // This Fires
socket.emit('joinRoom', {room: lobbySelect.value, class: characterSelect.value, player: player});
enteringRoom = false;
}
camera.position.x = 0; // updates the position of a camera
camera.position.z = -50;
}
socket.on('newJoin', (data) => {
console.log('someone has joined the room');
console.log(data);
})
socket.on('success', (res) =>{
console.log(res);
})
socket.on('addPlayers', (data) => {
console.log("Adding Players...");
for(let i = 0; i< data.length; i++){
console.log[i];
console.log("ADDING A PLAYER");
console.log(data[i]);
data[i].loadAssets();
playersInLobby += 1;
}
console.log(playersInLobby);
})
The problem is that nothing in the joinRoom event actually activates on the server end. None of the console logs even go off. The server however is able to console.log the socket.id on connection; that part works. Any ideas why it's not working?
Edit: This also causes the browser tab to freeze up and eventually crash
Related
I'm doing this code that emits from serverside and listens from clientside, The connection never ends until the client refresh or exits the page but that is not the case, the thing is that the code on clientside doesn't get execute and no error is showing on the logs.
ServerSide Code:
io.on('connection', function(socket) {
console.log("New socket connection");
socket.on('joinApp', ({msg, password}) =>{
let username;
let rooms;
model.findOne({username: msg}, function(err, found){
if(!err){
var checka = false;
if(found){
if(found.password === password){
user = userLogged(socket.id, msg, found.rooms);
username = getUserName(socket.id).username;
rooms = getUserName(socket.id).rooms;
console.log(msg + " Has entered the chat");
console.log(socket.id);
checka = true;
}else{
console.log("Incorrect password");
}
}else{
console.log("User not found");
}
io.to(socket.id).sockets.emit("checker", checka);
}
});
socket.on('myRooms', () =>{
let user = getUserName(socket.id);
let username = user.username;
let rooms = user.rooms;
if(user.rooms.length === 0){
console.log(username + " You have no rooms");
socket.emit("yourRooms", {username, rooms});
}else{
}
});
socket.on('disconnect', () => {
console.log("Disconnected");
});
});
});
This is the code i have on my express js file, if you see here:
io.to(socket.id).emit("yourRooms", {username, rooms});
The line above is where the problem is, i am emitting the signal that i'm going to listen clientside but the client don't listen to it (Clientside code below):
let title = document.getElementById("title");
let rooms = document.getElementById("rooms");
console.log(socket.id);
socket.on("yourRooms", (username, rooms) => {
if(rooms.length === 0){
rooms.innerHTML = "You have no rooms";
}
title.innerHTML = user + "'s rooms";
});
This part of the code will print the exact socket.id of the client so no problem here.
console.log(socket.id);
I'm not declaring another socket instance since that way it didn't work
I'm using this exact approach in another part of my code and it is working, it's in the file where I created my socket instance:
const socket = io();
I've been trying for hours, no error in the logs and the socket.id is correct when I console.log in the clientside script where I'm having problems, so I don't know what am I doing wrong.
You are emitting an object in express
io.to(socket.id).emit("yourRooms", {username, rooms});
And you are listening for different arguments in client side
socket.on("yourRooms", (username, rooms) => {
Try changing it to
socket.on("yourRooms", ({username, rooms}) => {
so I'm emitting an event from my client that sends a string containing the socket/roomID I'm trying to connect to in it. When the data is received, it's handled by this code on the server side:
const express = require('express');
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const port = process.env.PORT || 3000;
app.use(express.static(__dirname + '/public'));
//runs when the user connects to the server
function onConnection(socket){
console.log('a user connected');
// socket.join('some room');
console.log('Created Room: ' + socket.id);
socket.emit("RoomID", socket.id);
socket.on("location", (receivedString) => {
// socket.emit("RoomID", socket.id);
socket.to(socket.id).emit("redirectLocation", receivedString);
console.log('\nReceived the following data from socket "' + socket.id + '": ' + receivedString);
console.log('The amount of people in this room is ' + io.sockets.adapter.rooms.get(socket.id).size + '.');
});
//runs when the user is trying to join a specific room
socket.on("joinRoom", (roomIdentifier) => {
console.log('The room identifier is: ' + roomIdentifier);
console.log('The room is already in the rooms array: ' + io.sockets.adapter.rooms[String(roomIdentifier)]);
if (io.sockets.adapter.rooms[roomIdentifier]) {
socket.join(roomIdentifier);
} else {
console.log(socket.id + 'tried to join ' + roomIdentifier + 'but the room does not exist.');
};
});
socket.on('disconnect', onDisconnection);
}
//runs when the user disconnects from the server
function onDisconnection(socket){
console.log('a user disconnected');
}
//runs when the socket manager registers a connection
io.on('connection', onConnection);
//Runs when a new room was created
io.of("/").adapter.on("create-room", (room) => {
console.log(`room ${room} was created`);
});
io.of("/").adapter.on("join-room", (room, id) => {
console.log(`socket ${id} has joined room ${room}`);
});
http.listen(port, () => console.log('listening on port ' + port));
I don't know why it's coming out as undefined--I thought maybe it was because the rooms dictionary wasn't supposed to have a string or something as a key but I'm really not sure.
There are two problems in the code shared:
Check whether a room already exists
The following command shows that io.sockets.adapter.rooms is a JavaScript Map object.
console.log(io.sockets.adapter.rooms)
// returns [object Map]
To check whether the Map contains the room name, the Map.has(key) should then be used, instead of Map[key]:
io.sockets.adapter.rooms.has(roomIdentifier)
Once the room existence checks are adapted as above, the code still fails to let users join a room, as explained below.
Joining a room
The if statement lets the user join a room only if the room already exists, and does nothing otherwise. As a consequence, rooms are never created, and hence no user can ever join any of them.
if (io.sockets.adapter.rooms.has(roomIdentifier)) {
socket.join(roomIdentifier);
} else {
console.log(socket.id + 'tried to join ' + roomIdentifier + 'but the room does not exist.');
// Socket.join is not executed, hence the room not created.
};
socket.join should be executed outside of the if statement. The if statement can probably be removed from the code, unless some specific action needs to be taken depending on it.
if (io.sockets.adapter.rooms.has(roomIdentifier)) {
// action when room already exists
} else {
console.log(socket.id + 'tried to join ' + roomIdentifier + 'but the room does not exist.');
// action when room is new
};
// join the room in any case
socket.join(roomIdentifier);
Try using io.sockets.adapter.rooms.get(roomId) io.sockets.adapter.rooms returns a Map Object so using io.sockets.adapter.rooms[roomId] returns undefined.
I am trying to send the contents of a text file through a socket connection every time the text file updates using Express:
console.log('Server running!');
var express = require('express');
var app = express();
var server = app.listen(3000);
var fs = require("fs");
var x = 0;
app.use(express.static('public'));
var socket = require('socket.io');
var io = socket(server);
io.sockets.on('connection', newConnection);
function newConnection(socket) {
console.log("New connection: " + socket.id);
while (true) {
fs.readFile('song.txt', function(err, data) {
if (err) throw err;
console.log(data);
if (data != x) {
var songdata = data;
console.log(songdata);
io.sockets.emit('update', songdata);
x = data;
} else {
console.log("Song is not different:)");
}
})
}
}
Without the while loop, everything works just fine and I recieve the contents in the seperate client. However, now nothing is happening, no console log of data. This indicates the readFile is suddenly no longer running, why?
Thanks:)
First off, some basics. node.js runs your Javascript as single threaded and thus this is a single threaded server. It can only do one thing with your Javascript at a time. But, if you program it carefully, it can scale really well and do lots of things.
Second off, you pretty much never want to do while (true) in server-side Javascript. That's just going to run forever and never let anything else run on your server. Nothing else.
Third, you are attempting to create a new version of that infinite loop every time a new client connects. That's not a correct design (even if there wasn't an infinite loop). You only need one instance of code checking the file, not N.
Now, if you what you're really trying to do is to "poll" for changes in song.txt and notify the client whenever it changes, you need to pick a reasonable time delta between checks on the file and use a timer. This will check that file every so often and let your server run normally all the rest of the time.
Here's a simple version that polls with setInterval():
console.log('Server code started!');
const express = require('express');
const app = express();
const server = app.listen(3000);
const fs = require("fs");
let lastSongData = 0;
app.use(express.static('public'));
const io = require('socket.io')(server);
// get initial songData for future use
// there will not be any connected clients yet so we don't need to broadcast it
try {
lastSongData = fs.readFileSync('song.txt');
} catch(e) {
console.log(e, "\nDidn't find song.txt on server initialization");
}
// here, we create a polling loop that notifies all connected clients
// any time the song has changed
const pollInterval = 60*1000; // 60 seconds, ideally it should be longer than this
const pollTimer = setInterval(() => {
fs.readFile('song.txt', (err, songData) => {
if (!err && songData !== lastSongData) {
// notify all connect clients
console.log("found changed songData");
io.emit('update', songData);
lastSongData = songData;
}
});
}, pollInterval);
io.sockets.on('connection', socket => {
console.log("New connection: " + socket.id);
});
If your songData is binary, then you will have to change how you send the data to the client and how you compare the data to the previous data so you are sending and receiving binary data, not string data and so you are comparing buffers, not strings.
Here's are some references on sending binary data with socket.io:
How to send binary data with socket.io?
How to send binary data from a Node.js socket.io server to a browser client?
A little more efficient way to detect changes to the file is to use fs.watch() which should notify you of changes to the file though you will have to thoroughly test it on whatever platform you are running to make sure it works the way you want. The feature has a number of platform caveats (it does not work identically on all platforms), so you have to test it thoroughly on your platform to see if you can use it for what you want.
console.log('Server code started!');
const express = require('express');
const app = express();
const server = app.listen(3000);
const fs = require("fs");
let lastSongData = 0;
app.use(express.static('public'));
const io = require('socket.io')(server);
// get initial songData for future use
// there will not be any connected clients yet so we don't need to broadcast it
try {
lastSongData = fs.readFileSync('song.txt');
} catch(e) {
console.log(e, "\nDidn't find song.txt on server initialization");
}
// ask node.js to tell us when song.txt is modified
fs.watch('song.txt', (eventType, filename) => {
// check the file for all eventTypes
fs.readFile('song.txt', (err, songData) => {
if (!err && songData !== lastSongData) {
// notify all connect clients
console.log("found changed songData");
lastSongData = songData;
io.emit('update', songData);
}
});
});
io.sockets.on('connection', socket => {
console.log("New connection: " + socket.id);
});
It is unclear from your original code if you need to send the songData to each new connection (whether it has recently changed or not).
If so, you can just change your connection event handler to this:
io.sockets.on('connection', socket => {
console.log("New connection: " + socket.id);
// send most recent songData to each newly connected client
if (lastSongData) {
socket.emit('update', lastSongData);
}
});
Continuously reading the file to detect changes is not a good idea. Instead you should use fs.watch(filename[, options][, listener]) to notify you when the file has changed. When a new socket connects only that socket should have the content broadcast to them, sending it to every client is redundant.
io.sockets.on('connection', newConnection);
var filename = 'song.txt';
function update(socket) {
fs.readFile(filename, function (err, data) {
if (err) throw err;
socket.emit('update', data);
});
}
function newConnection(socket) {
console.log("New connection: " + socket.id);
update(socket); // Read and send to just this socket
}
fs.watch(filename, function () {
console.log("File changed");
update(io.sockets); // Read and send to all sockets.
});
I use socket.io and node-google package to retrieve google search results and send theme to socket.io clients, now i want to know if there is a way to open google request synchronously (in sequential order) and emit a socket to the clients when all search request are done ?
here is my code :
// Load google package
var google = require('google');
// Load socket.io package
var io = require('socket.io').listen(8080);
// on connection
io.sockets.on('connection', function (socket) {
console.log('client connected !');
// on request
socket.on('request', function (keywords) {
keywords.forEach(function(entry, index){
// get results
google.resultsPerPage = 10;
google.tld = 'fr';
var nextCounter = 0;
// how to make google function sync
google(entry, function (err, next, links){
if (err) console.error('-----\n' + err + '\n-----');
for (var i = 0; i < links.length; ++i) {
res = links[i].title + links[i].description;
if(res){
socket.emit('response', res);
}
}
if (nextCounter < 4) {
nextCounter += 1;
if (next) next();
}
});
// all search keywords are done (not working)
if(index === keywords.length - 1){
socket.emit('response', '------ all done ------');
}
});
});
});
Thanx :)
I am using node.js with cluster module in order to create multiprocess socket.io server.
Using this example I have created the following server-client application:
Server:
var cluster = require('cluster');
// Start master process
if (cluster.isMaster) {
// Create slave workers (in this example there is only one)
var worker = cluster.fork();
// Starts a server that will delegate the connection to the worker
var routerServer = net.createServer(function(connection) {
worker.send({type: 'new_connection'}, connection);
});
routerServer.listen(443, "my-ip-address");
} else {
// Start a server on random Port
var slaveHttp = require("http").Server();
slaveHttp.listen(0, "localhost");
// Connect socket.io to the server
var io = require('socket.io')(slaveHttp);
io.on('connection', function (socket) {
console.log("Connected");
});
// On server messsage (new connection) emit it to the server
process.on('message', function(message, handle) {
if (message.type == 'new_connection') {
slaveHttp.emit('connection', handle);
};
});
}
Client:
var io = require('socket.io-client');
function connect(index) {
connection = io.connect("http://my-ip-address", {
reconnection: true,
reconnectionDelay: 1000,
timeout: 3000,
multiplex: false });
connection.on('connect', function (socket) {
console.log(index + ': Connected');
});
connection.on('connect_error', function (e) {
console.log(index + ': Connection Error: ' + e);
});
connection.on('message', function () {
console.log(index + ': Server message');
});
connection.on('disconnect', function () {
console.log(index + ': disconnect');
});
}
for (var i = 0; i < 10; i++) {
setTimeout(function(index) {
return function() { connect(index); }
}(i), i * 5000);
};
The problem is that some of the clients in the above example managed to connect to the server and exchange messages, but the others failing on timeout, weirder then that I can see in the server's console that it received the connections for the timed-out clients but for some reason they don't succeed to communicate.
If I replace the server code to be on the same process this code runs perfectly.
Can anyone help me?
I found out this is a bug in Node.js, the problem is that there is auto-read machanism in Node.js sockets that starts to read out of every new socket automatically.
When we pass the socket to the child process it can either been read already or not, under heavy load there is more change that the socket will be read by the master (which of course is cuasing the problem), therefore we should explicitly ask to stop reading from this socket.
The following line is a nice workaround (should be added just before worker.send call):
connection._handle.readStop();
Source: https://github.com/joyent/node/issues/7905