nodejs, socket, https - Socket makes no connection but only disconnects - javascript

I've been through A LOT of issues in here about this topic but so far no answers has been the solution for my problem.
My setup is an AWS EC2 server with apache installed. I've installed node.js in the /node folder containing a server-file called server.js and in the root folder I have my client-file index.php. I have Let´s Encrypt SSL-certificates for my domain and therefore I need everything to run over https. I have opened up the port 3000 for all traffic en AWS.
Server.js
const app = require('express')();
const fs = require('fs');
const options = {
key: fs.readFileSync("/etc/letsencrypt/live/example.com/privkey.pem"),
cert: fs.readFileSync("/etc/letsencrypt/live/example.com/fullchain.pem")
};
const http = require('https').Server(options, app);
const io = require('socket.io')(http);
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
});
});
http.listen(3000, function(){
console.log('listening on 3000');
});
index.php
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Socket Test</title>
</head>
<body>
<ul id="events"></ul>
<script src="https://cdn.jsdelivr.net/npm/socket.io-client#2/dist/socket.io.js"></script>
<script>
const events = document.getElementById('events');
const newItem = (content) => {
const item = document.createElement('li');
item.innerText = content;
return item;
};
const socket = io('https://example.com:3000', {transports: ['websocket', 'polling']});
console.log(socket);
socket.on('connect', () => {
console.log("did connect");
events.appendChild(newItem('connect'));
});
socket.on('disconnect', () => {
console.log("did disconnect");
});
</script>
</body>
</html>
The problem
When I start my node server everything seems right. Executing node server.js returns listening on 3000 as supposed. When I go to index.php it never returns did connect BUT when I then exit the server node I get the did disconnect message in the browser console.
Also the server never returns anything else but listening on 3000.
Please help me :-)

Since the recent update to v3.0.0, version 2.x.x clients are not compatible so won't be able to connect.
The fix is to make sure both client and server are using the same versions, or use the server served version /socket.io/socket.io.js (which is not always possible, webpack etc)
Related issue on github: https://github.com/socketio/socket.io-client/issues/1390

Related

Express.js: How to refresh on DB change in backend?

I decided to make a janky chat site type thing to get me started working with requests and such.
My approach was to create an express.js server that takes in requests when the '/messageReciever' is posted to.
app.post("/messageReciever", (req, res) => {
logMessage(req.body.message);
});
The next step was to make a 'client' that could send information to this end point:
var XMLHttpRequest = require("XMLHttpRequest").XMLHttpRequest;
function makePostRequest(url, json)
{
let http = new XMLHttpRequest();
http.open("POST", url, true);
http.setRequestHeader("Content-Type", "application/json");
http.send(JSON.stringify(json));
}
function sendMessage(url, message)
{
makePostRequest(url, {message: message});
logMessage(message);
}
Both of these are fine. The issue I'm running into is, once I receive the post request I want to refresh the main page of my site (to show the messages)
app.get('/', (req, res) => {
res.render('index', data = retrieveMessages());
});
I've tried basically everything I've found online:
res.redirect('back');
res.redirect(req.get('referer'));
res.redirect(req.originalUrl)
I used res.redirect('back') previously in my code, and it works. The issue is that I'm trying to refresh someone's connection to a site based on someone else's connection; meaning I can't use the response information like I normally could.
I've tried looking for ways to refresh pages from outside functions but I can't find anything.
(I realize that there are easier ways to make a chat site that don't include weirdly sending data back and forth between two server's)
You can use a package called socket.io. Socket.io allows you to send requests to a client once the server has some data.
Example:
Server:
// Define express
const express = require('express');
const app = express();
// Create the server
const http = require('http');
const server = http.createServer(app);
// Define socket.io
const io = require('socket.io')(server);
// Define the port for the server to listen on
let port = 3000;
function logMessage(message, id) {
...
io.emit('message_sent_' + id, { message }); // Emit that a message was sent to the clients
}
function recieveMessages(id) {
// Get the messages somehow
}
app.post('/messageReciever', (req, res) => {
// req.body.message is your message and req.cookies.id is the clients random ID
logMessage(req.body.message, req.cookies.id);
});
app.get('/', (req, res) => {
res.cookie('id', 'some-generated-id'); // Set a cookie for the unique ID to fetch user messages
res.render('index', { data: retrieveMessages() });
});
// Get the server listening to incoming requests
server.listen(port, () => console.log('my app is online');
Client:
<!doctype html>
<html>
<body>
...
</body>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io.connect();
socket.on('message_sent_' + 'some-id', function(data) {
// Do something with the data
});
</script>
</html>
References:
https://socket.io/docs/v4/
http://expressjs.com/
https://marques-robinson-project.medium.com/chat-app-with-socket-io-and-express-using-node-js-2293b87f47c3

Trying to send a string message from javascript server to client using sockets; when pressing HTML button

I am new to this area so forgive me if I fail to explain my question well.
I am essentially trying to send a string "Hello, I connected to the port" to my Javascript client, only when I have pressed a HTML button.
FOR TESTING PURPOSES:
I have been successful in running a client and server Javascript socket connection, and can receive data back and forth. However when trying to link this to my html page I fail to connect them and send data.
CLIENT.JS:
const net = require('net');
const client = net.createConnection({ port: 9898 }, () => {
console.log('CLIENT: I connected');
client.write('CLIENT: Hello this is client!');
});
client.on('data', (data) => {
console.log(data.toString());
client.end();
});
client.on('end', () => {
console.log('CLIENT: I disconnected from the server.');
});
SERVER.JS
const net = require('net');
const server = net.createServer((socket) => {
socket.on('data', (data) => {
console.log(data.toString());
});
socket.write('SERVER: Hello! \n');
socket.end('SERVER: Closing connection now \n');
}).on('error', (err) => {
console.error(err);
});
server.listen(9898, () => {
console.log('opened server on', server.address().port);
});
if you save the above code and run them using the lines:
node server.js
node client.js
You will find that they send messages between them quite nicely.
The issue starts when I try to run my html page (which is served using node.JS on port 8083)
(I server my HTML page using npx http-server --cors)
An approach I tried was to place the code in client.js into a function and then call it in my html button:
<input type = "button" onclick = "outputData()" value = "Display">
(outputData being the function that contains the code in client server)
I'm not sure if its even something that can be done, but I'd like to essentially start my server.js from my HTML page, when a button is clicked, so that it can begin sending the data. I'd want to run "node client.js" on terminal and see that messages are coming through as server.js would have been started from my webpage
Any advice would be highly appreciated. Thank you for taking the time.
Information about socket.io library, https://socket.io/docs/v3/client-api/index.html
Sending message index.html
<html>
<body>
<input type="button" onclick="javascript:sendMessage()" value="Click here"/>
<script>
const sendMessage = () => {
var new_message = {message: "this is my message"}
socket.emit('new_message', new_message);
}
</script>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io("http://localhost:8080");
</script>
</body>
</html>
server.js
socket.on('new_message', (data) => {
var New_Details = {
message: data.message
};
socket.broadcast.emit('update_message', New_Details);
console.log(data.username + ' just wrote ' + data.message);
});
I managed to solve this by using Websockets. Where my webserver acted as the client, and I adjusted my server.js to the following:
SERVER.JS
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 9898 });
wss.on("connection", ws => {
console.log("New client connected!");
ws.on("message", data => {
console.log(`Client has sent us: ${data}`);
ws.send(data.toUpperCase());
});
ws.on("close", () => {
console.log("Client has disconnected!");
});
});
HTML
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/assets/dcode.css">
<link rel="shortcut icon" href="/assets/favicon.ico" type="image/x-icon">
<title>WebSockets</title>
</head>
<body>
<script>
const ws = new WebSocket("ws://localhost:9898");
ws.addEventListener("open", () => {
console.log("We are connected!");
ws.send("Hey, how's it going?");
});
ws.addEventListener("message", ({ data }) => {
console.log(data);
});
</script>
</body>
</html>

socket io not receiving events for both client and server

I followed the socket io website and implement client and server, below is my code
server
const exp = require('express')();
const http = require('http').createServer(exp);
const io = require('socket.io')(http,{
cors : {
origin : '*'
}
});
http.listen(3000, () => {
console.log('listening on *:3000');
setInterval(function(){
io.sockets.emit('hi', 'everyone');
},1000);
io.sockets.on('connection', function (socket) {
socket.on('hello', function (msg) {
console.log(msg);
});
});
});
client
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.4.0/socket.io.js" integrity="sha512-Y8KodDCDqst1e8z0EGKiqEQq3T8NszmgW2HvsC6+tlNw7kxYxHTLl5Iw/gqZj/6qhZdBt+jYyOsybgSAiB9OOA==" crossorigin="anonymous"></script>
<script>
let socket = io('http://localhost:3000',{
transports : ['websocket']
});
socket.on('hi', function(msg) {
console.log(msg);
});
socket.emit('hello','Hello server, im client');
socket.on('connect', function() {
console.log(socket.connected); // true
});
</script>
neither event hi nor hello arrived nor received from and to both client and server, no error whatsoever when running the script and client connecting to server. Any help is greatly appreciated.
Make sure to use matching socket.io versions: On your client you use 2.4.0, so install the same version on your server (npm install socket.io#2.4.0).
In the changelog for 2.4.0 you can see how you have to set cors options:
const io = require('socket.io')(http, { origins: "http://localhost:5000" });
You can't use "*" anymore, use your client domain. In newer versions the interface changed.
If you're not using version 2.4.0, the problem could also be the "*" wildcard.

socket.io not sending to client

I am trying to create a simple script to send data from a file every to the client every time the file is updated. I have tested and found that the file is read, but the client doesn't receive anything. there are no errors in the console. I am fairly new to socket.io.
node.js code
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require("fs");
var port = process.env.PORT || 3000;
app.get('/', function(req, res){
res.sendFile(__dirname + '/popup.html');
});
fs.watchFile("assets/popup.json", {interval:100}, function(curr, prev)
{
fs.readFile("assets/popup.json",{encoding:"utf8"}, function(err, data){
io.emit("popup", data)
})
});
http.listen(port, function(){
console.log('listening on *:' + port);
});
client code
var socket = io();
socket.on('popup', function(msg){
alert("hello")
});
Whenever things aren't working right like this, you need to resort to "debug mode". In that mode, you need to gather all possible events that might be happening and see what you learn from that. To that end, add this code to the client:
var socket = io();
socket.on('popup', function(msg){
console.log("hello: ", msg)
});
socket.on('connection', function() {
console.log("client connected");
});
socket.on('connect_error', function(err) {
console.log("client connect_error: ", err);
});
socket.on('connect_timeout', function(err) {
console.log("client connect_timeout: ", err);
});
These messages are all documented in the client-side doc on the socket.io Github site which you can find by Googling "socket.io github" at any time.
Then, see what you see in the browser console when the page loads. If you don't know how to open the browser console in whichever browser you are using, google it to find out. You need to be looking at the debug console when the page loads.
FYI, we're assuming that you've loaded socket.io into the page via a script tag before this code. If not, that error will show in the console too.
The OP then gets this error:
client connect_error:
Error: server error at Socket.onPacket (socket.io-1.2.0.js:1)
at XHR.<anonymous> (socket.io-1.2.0.js:1)
at XHR.Emitter.emit (socket.io-1.2.0.js:1)
at XHR.Transport.onPacket (socket.io-1.2.0.js:1)
at callback (socket.io-1.2.0.js:2)
at Object.exports.decodePayload (socket.io-1.2.0.js:2)
at XHR.Polling.onData (socket.io-1.2.0.js:2)
at Request.<anonymous> (socket.io-1.2.0.js:2)
at Request.Emitter.emit (socket.io-1.2.0.js:1)
at Request.onData (socket.io-1.2.0.js:2)
OK, progress. How are you loading socket.io in the client page? This seems like it might be that you have mismatched versions of socket.io in client and server. You should be doing:
<script src="/socket.io/socket.io.js"></script>
and then your server will be feeding the client page the exact same version of socket.io. Also, since this error reports client-side socket.io 1.2.0, what version of socket.io is installed on the server?
try this
socket.on('popup', function(msg){
socket.emit('message',"popup");
});
The issue appears to be you don't actually connect to a local socket.io server. By running node server.js with the code below you can start a web server. Then navigate to localhost in your browser to see the changes in console made to popup.json.
server.js
var app = require('http').createServer(handler);
var io = require('socket.io')(app);
var fs = require('fs');
app.listen(80);
function handler (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);
});
}
fs.watchFile("popup.json", {interval: 100}, function (curr, prev) {
fs.readFile("popup.json", {encoding: "utf8"}, function (err, data) {
io.emit("popup", JSON.parse(data));
})
});
index.html
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io('http://localhost');
socket.on('popup', function (data) {
console.log(data);
});
</script>

How do I properly emit data to server from client using Node.js?

When the client connects to the server a message is supposed to be emitted to the console. I'm not getting any errors so I'm confused as to what my problem actually is.
Server: As you can see the client connects.
Client: The message doesn't appear in the console.
(Forgive me for the links, I don't have 10 reputation)
How do I get the message to print to the console?
I've read other posts like this one, but they weren't helpful :(
When you do io.connect(), that call is asynchronous and not immediate. You cannot immediately emit to the server until the client generates the connect event:
var socket = io.connect()
socket.on('connect', function() {
// it is safe to call `.emit()` here
socket.emit("sndMsg", someData);
});
index.html
<html>
<head>
<script src='/socket.io/socket.io.js'></script>
<script>
var socket = io();
socket.on('welcome', function(data) {
addMessage(data.message);
// Respond with a message including this clients' id sent from the server
socket.emit('i am client', {data: 'foo!', id: data.id});
});
socket.on('time', function(data) {
addMessage(data.time);
});
socket.on('error', console.error.bind(console));
socket.on('message', console.log.bind(console));
function addMessage(message) {
var text = document.createTextNode(message),
el = document.createElement('li'),
messages = document.getElementById('messages');
el.appendChild(text);
messages.appendChild(el);
}
</script>
</head>
<body>
<ul id='messages'></ul>
</body>
</html>
server.js
var http = require('http'),
fs = require('fs'),
// NEVER use a Sync function except at start-up!
index = fs.readFileSync(__dirname + '/index.html');
// Send index.html to all requests
var app = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(index);
});
// Socket.io server listens to our app
var io = require('socket.io').listen(app);
// Send current time to all connected clients
function sendTime() {
io.emit('time', { time: new Date().toJSON() });
}
// Send current time every 10 secs
setInterval(sendTime, 10000);
// Emit welcome message on connection
io.on('connection', function(socket) {
// Use socket to communicate with this particular client only, sending it it's own id
socket.emit('welcome', { message: 'Welcome!', id: socket.id });
socket.on('i am client', console.log);
});
app.listen(3000);

Categories

Resources