Node SocketIo - Client not emitting? - node.js

I'm having issues with Node SocketIo client not emitting data. So when the client connects in the index.html does log the "Connected This Is A Test", however it does not socket.emit('cool'), no errors nor does it seem to log on server.js. I'm not sure why its not emitting or the server isnt listening.
Server.js
const path = require('path');
const http = require('http');
const express = require('express');
const socketio = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketio(server);
const PORT = 3002;
app.use(express.static(path.join(__dirname, 'public')));
// run when client connects
io.on('connection', () => {
console.log('New WS connection...');
io.emit('connection', 'This Is A Test');
});
io.on('cool', (msg) => {
console.log(msg);
});
server.listen(PORT, () => console.log(`server running on port ${PORT}`));
index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://' + document.domain + ':' + location.port);
socket.on('connection', function(data){
console.log("connected", data);
socket.emit('cool', 'MSG');
});
</script>
</body>
</html>

On your server, you need to be listening for the cool message on a specific connected socket, not on the io object. The io object does not have specific socket messages other than announcing a newly connected socket. To listen for messages from a specific socket, you need a listener on the connected socket itself. The usual place to add that listener is in the connection event where you are presented with the newly connected socket object.
So change this:
// run when client connects
io.on('connection', () => {
console.log('New WS connection...');
io.emit('connection', 'This Is A Test');
});
io.on('cool', (msg) => {
console.log(msg);
});
to this:
// run when client connects
io.on('connection', (socket) => {
console.log('New WS connection...');
// send a test event back to the socket that just connected
socket.emit('test', 'This Is A Test');
// listen for the cool message on this new socket
socket.on('cool', (msg) => {
console.log(msg);
});
});
Also, you really should not be emitting event names used by the system like connection. That's why I changed the event name to test so it won't conflict with names that socket.io itself is using.

Related

Socket.io client responds only once

I am creating an express server which will cause the index.html page to redirect to a new page on receiving a post request. Everything works fine, but only for the first time. I have to restart the server regularly for it to work. Here are some code snippets.
//server.js
const app = express();
app.use(express.static(`${__dirname}/public`));
const server = http.createServer(app);
const io = socketIo(server, {'force new connection': true });
io.on('connection', (socket) => {
console.log('New client connected');
app.post('/redirect', (req,res) => {
socket.emit('redirect');
res.status(200).send('Redirected');
});
});
<body>
<!-- Jquery CDN -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<!-- Socket.IO -->
<script src="/socket.io/socket.io.js"></script>
<script>
let socket = io.connect({'force new connection': true });
socket.on('connect', () => {
console.log('Connected to Server');
});
socket.on('redirect', () => {
window.location.replace("https://google.com");
});
</script>
</body>
The main issue, is that you have your route inside the socket connection listener. A route should be only registered once. And connection is triggered multiple times.
const app = express();
app.use(express.static(`${__dirname}/public`));
const server = http.createServer(app);
const io = socketIo(server, {'force new connection': true });
app.post('/redirect', (req,res) => {
res.status(200).send('Redirected');
io.emit('redirect');
// io.to(someSocketOrRoom).emit('redirect');
});
io.on('connection', (socket) => {
console.log('New client connected');
});
If you want to emit to the socket when you receive a message from outside the socket, in this case an HTTP Post. You need to use io.emit to emit to all sockets, or io.to().emit to emit to a specific one.
Now, it doesn't make much sense to redirect using socket.io, if you're posting to /redirect why don't you just redirect the user using res.redirect, without emitting anything.

Chat application using socket.io not connecting when deploying on production server

I am trying to implement chat application using nodejs and socket.io. The application works on localhost. But when I deploy same on my production server then socket.io can't make any connection.
Code for server.js
var express = require('express');
var app = express();
var socket = require('socket.io');
var chat_controller = require('./controllers/ChatController.js');
var user_controller = require('./controllers/UserController.js');
var Group_controller = require('./controllers/GroupChatController.js');
app.get('/search', function (req, res) {
user_controller.get(req, res);
});
app.get('/groupSearch', function (req, res) {
user_controller.get(req, res);
});
var server = app.listen(3600, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
});
var io = socket(server);
io.on('connection', (socket) => {
console.log('made socket connection', socket.id);
socket.broadcast.emit('userconnected');
chat_controller.respond(io, socket);
Group_controller.respond(io, socket);
user_controller.respond(io, socket);
});
io.on('disconnect', function () {
console.log('made socket disconnect', socket.id);
});
Code for client.js
var socket = io.connect('https://www.mywebsite.com', {
path: '/apichat'
});
/* Other events related to socket. */
As my server uses SSL I can't used IP:PORT directly so I am using ProxyPass as
ProxyPass /apichat http://127.0.0.1:3600
After all this still socket connection is not established between server and client.
Error shown in browser console is:
POST https://www.mywebsite.com/apichat/?EIO=3&transport=polling&t=MUc-TJK 404 (Not Found)
And in browser Network tab it shows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /</pre>
</body>
</html>
I have checked many other questions posted here and other sites but no question address this issue.
Please Help.
The issue you are encountering is probably due to ssl enabled on your website.
You need to pass ssl related files in your app.js file. Sample code for this is as follow:
var fs = require('fs');
var options = {
key: fs.readFileSync('PATH_TO_SSL_KEYS.key'),
cert: fs.readFileSync('PATH_TO_SSL_CERTS.crt'),
ca: fs.readFileSync('PATH_TO_SSL.pem')
};
var app = require('https').createServer(options, handler), io = require('socket.io').listen(app);
io.set('transports', [
'websocket',
'flashsocket',
'htmlfile',
'xhr-polling',
'jsonp-polling',
'polling'
]);
function handler(req, res) {
res.writeHead(200);
res.end("welcome sir!");
}
var chat_controller = require('./controllers/ChatController.js');
var user_controller = require('./controllers/UserController.js');
io.sockets.on('connection', function (socket) {
socket.broadcast.emit('userconnected');
chat_controller.respond(io, socket);
user_controller.respond(io, socket);
socket.on('message', function (data) {
socket.broadcast.emit('message', data);
});
});
io.on('disconnect', function (socket) {
console.log('made socket disconnect', socket.id);
});
app.listen(3300);
Try editing your application file as per above mentioned sample code and then try to use it. If you can't get path to ssl related file, then you need to contact either your system administrator or the hosting provider.
I hope it helped.

Communicating TCP with HTTP in Socket.io getting TypeError: Cannot read property 'emit' of undefined

Trying to communicate TCP server with HTTP server
My TCP port is 4040 and HTTP port is 3000
I am working on passing data received on TCP server to HTTP server
Data received on TCP port is showing on console window and I am trying to pass this data to HTTP by storing data in global var so that I can display it on the webpage.
Thanks :)
server code:
enter code here var http = require('http').createServer(httpHandler);
var net = require('net');
var app = require('express')(); <!-- These are mandatory variables -->
var http = require('http').Server(app);
var io = require('socket.io')(http);
var sockets = [];
var HOST = 'localhost';
var PORT = 4040;
global.MYVAR = "Hello world";
global.MYVAR2 = "Hello world";
var server = net.createServer();
server.listen(PORT, HOST);
// Keep track of the chat clients
var clients = [];
/**
* http server
*/
function httpHandler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
app.get('/', function(req, res){ <!-- This sends the html file -->
//send the index.html file for all requests
res.sendFile(__dirname + '/index.html');
});
http.listen(3000, function(){ <!-- Tells the HTTP server which port to use -->
console.log('listening for HTTP on *:3000'); <!-- Outputs text to the console -->
console.log('listening for TCP on port ' + PORT);
});
<!-- everything below this line is actual commands for the actual app -->
io.on('connection', function(socket) // Opens the socket
{
socket.on('checkbox1', function(msg){ // Creates an event
console.log(msg); // displays the message in the console
MYVAR = msg; // Sets the global variable to be the contents of the message recieved
for (var i = 0; i < sockets.length; i++) {
if(sockets[i]) {
sockets[i].write(MYVAR, 'utf-8');
}
}
});
});
server.on('connection', function(socket){ // Opens the socket for the TCP connection
sockets.push(socket);
socket.write(MYVAR, 'utf-8');
// Handle incoming messages from clients.
socket.on('data', function (data) {
broadcast(socket.name + "> " + data, socket);
});
// Send a message to all clients
function broadcast(message, sender) {
MYVAR2 = message;
console.log(MYVAR2);
socket.broadcast.emit('updateHeader',MYVAR2); // GETTING ERROR HERE
}
}).listen(PORT, HOST);
index.html code:
<!doctype html>
<html>
<head>
<title>Socket IO Test</title>
</head>
<body>
<h1 id="h1">Hello World</h1>
<form action="">
<input type='checkbox' onclick='checkbox1(this);'>Checkbox1</label>
</form>
<script src="/socket.io/socket.io.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io();
var number = 0;
$(document).ready(function(){
socket.on('updateHeader',function(data){
console.log('updateHeader called');
document.getElementById('h1').innerHTML = data;
});
});
function checkbox1(cb) {
socket.emit('checkbox1', 'checkbox 1 = ' + cb.checked);
return false;
}
</script>
The problem is you're trying to use socket.io broadcast in a net.Socket which of course doesn't have that property.
server.on('connection', function(socket){ /* ... */ }
When a new TCP stream is established. socket is an object of type
net.Socket. Usually users will not want to access this event. In
particular, the socket will not emit 'readable' events because of how
the protocol parser attaches to the socket. The socket can also be
accessed at request.connection.
I don't know exactly what you're trying to achieve, but you can use io.emit if you want to send message to all clients.
function broadcast(message, sender) {
MYVAR2 = message;
//This will emit 'updateHeader' to all socket.io connected sockets
io.emit('updateHeader', MYVAR2);
//The 'socket' you were using here was a net.Socket not a socket.io one.
}
function broadcast(message, sender) {
MYVAR2 = message;
console.log(MYVAR2);
sender.broadcast.emit('updateHeader',MYVAR2); //Replace socket by sender here
}

Websocket connection in Node.js closes on sending

I tried many different npm web socket libraries (WebSocket, ws, express-ws and more), and in EVERYONE of them I have the same problem. When I try to send a websocket message, the connection closes.
I have no problem receiving messeges, only sending.
Here is one simple example of one test with express and ws libraries:
Node.JS side:
var server = require('http').createServer()
, url = require('url')
, WebSocketServer = require('ws').Server
, wss = new WebSocketServer({ server: server })
, express = require('express')
, app = express()
, port = 8080
, fs = require('fs');
app.use(function (req, res) {
var index = fs.readFileSync('./interface/index.html');
res.end(index);
});
wss.on('connection', function connection(ws) {
var location = url.parse(ws.upgradeReq.url, true);
console.log('open ws');
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send('test back');
});
ws.on('close', function () {
console.log('ws connection closed.');
})
});
server.on('request', app);
server.listen(port, function () { console.log('Listening on ' + server.address().port) });
and the browser side ("./interface/index.html"):
window.WebSocket = window.WebSocket || window.MozWebSocket;
var port = 8080;
var ip = window.location.hostname;
var connection;
connection = new WebSocket('ws://' + ip + ':' + port);
connection.onopen = function () {
// connection is opened and ready to use
console.log('Web socket connection with', ip + ':' + port);
//sendQueue(msgQueue);
};
connection.onerror = function (error) {
// an error occurred when sending/receiving data
console.log('Web socket erorr with', ip + ':' + port + ':', error);
};
connection.onmessage = function (message) {
// try to decode json (I assume that each message from server is json)
console.log("Received ws");
// handle incoming message
};
connection.onclose = function (){
console.log("Web socket connection lost.");
};
function sendws() {
connection.send("test");
console.log("sent ws");
return false;
}
<head>
<meta charset="utf-8">
<title>Simple Web Socket test</title>
<!--<meta name="description" content="Simple Web Socket">-->
<meta name="author" content="Binoman">
<link rel="stylesheet" href="css/styles.css?v=1.0">
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<button type="button" name="button" onclick="sendws()">Send</button>
</body>
I have no idea why this is happening. I updated Node.js to 6.7.
Running on windows 10.
I appreciate the help!
Thanks!
I discovered it was my antivirus's web protection that blocked the connection. I made an exception for my localhost address and it working perfectly now.

Raising a socket.io event from a Restify handler

I have a resitfy server and socketio server configured as per the example here.
My requirement is to raise a socket.io event from within a handler. So, my code looks like this:
var restify = require('restify');
var socketio = require('socket.io');
var server = restify.createServer();
server.get('/', function (req, res, next) {
res.json(204, null);
io.emit("sample", {"sample":"event"});
next();
});
server.listen(8080, function () {
console.log('socket.io server listening at %s', server.url);
});
My client code is pretty simple and looks like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Socket.IO Chat Example</title>
</head>
<body>
<script src="socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect('http://localhost:8080');
socket.on('sample', function (data) {
console.dir(data);
});
</script>
</body>
</html>
When I start the server, the server exists after the first time a client connects and this is found in the logs:
socket.io:server initializing namespace / +0ms
socket.io:server creating engine.io instance with opts {"path":"/socket.io"} +3ms
socket.io:server attaching client serving req handler +1ms
socket.io server listening at http://0.0.0.0:8080
socket.io:server incoming connection with id U9hLZRlbsGfvI8QPAAAA +2s
socket.io:client connecting to namespace / +4ms
socket.io:namespace adding socket to nsp / +0ms
http.js:690
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:690:11)
at ServerResponse.format (/home/vagrant/socket.io-server-example/node_modules/restify/lib/response.js:109:10)
at ServerResponse.send (/home/vagrant/socket.io-server-example/node_modules/restify/lib/response.js:231:24)
at emitRouteError (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:152:13)
at onRoute (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:610:21)
at Router.find (/home/vagrant/socket.io-server-example/node_modules/restify/lib/router.js:512:5)
at Server._route (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:604:21)
at routeAndRun (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:572:14)
at Server._handle (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:592:9)
at Server.onRequest (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:255:14)
What I am not able to understand is, how can I serve REST API and socket.io events from the same port using restify?
Why does restify complain about not being able to set headers once they are sent?
Am I missing something fundamental here?
Try using using this example
Pass the result from listen method to socketio and then use the io instance to send those events on your handlers.
var restify = require('restify');
var server = restify.createServer();
var app = server.listen(8080, function() {
console.log('%s listening at %s', server.name, server.url);
});
var io = require("socket.io")(app);
function respond(req, res, next) {
res.send('hello ' + req.params.name);
io.emit('sample',{"data":"hello from server."});
next();
}
server.get('/hello/:name', respond);
server.head('/hello/:name', respond);
io.on('connection', function(socket){
console.log('new connection');
});

Resources