Socket.IO on client side - node.js

I am creating a nodejs+express+socket.io server.
Also I created a scaffold via yeoman for my frontend app.
The socket.io server is on port 3000 and my yeoman scaffold http server on 9000.
I have managed to retrieve the socket.io.js from the socket.io server using
<script type="text/javascript" src="http://localhost:3000/socket.io/socket.io.js"></script>
However im having this error:
GET http://localhost:9000/socket.io/?EIO=3&transport=polling&t=1425392110184-42 404 (Not Found)
Why is the socket.io.js polling on port 9000?
Moreover, how can I change this so that it'll poll on 3000 instead?

The socket.io client takes an option URL argument. If not specified, it will connect using the current document origin. This means if the HTML document's URL is http://localhost:9000, then it will connect to http://localhost:9000. Specify it when you connect:
var socket = io('http://localhost:3000');
Instead of
var socket = io();

Okay I solved it by passing the url of the socket.io as parameter to the io() function.
var socket = io('http://localhost:3000');

Related

Error connecting to socket.io server, changed code from websocket to socket.io

I'm currently using websocket library on both nodejs backend and JS client.
I'm trying to change to socket.io, I managed to write the code for both sides however I'm unable to connect to the server from my client.
On the console of my browser I see the error and realised that the address is being changed by the socketio library.
websocket: wss://domain.com/asset-ws/ ==> works fine
socketio: auto changes the url to wss://domain.com/socket.io/?EIO=4&transport=websocket
The error: WebSocket connection to 'wss://domain.com/socket.io/?IO=4&transport=websocket' failed.
Is it something to do with my nginx config?
Any help would be much appreciated.
Thank you
By default socket.io url adds the /socket.io path.
In my Nginx config I'm already using a custom path add, so I just specified a path on the io server config, like so:
const io = new Server(server, {
path: '/'
});
This way the default path would be overwritten.

URL generated by SocketIO in NodeJS running locally

I'm using Socket.IO to run a WebSocket server locally in NodeJS using the following code:
import express = require('express');
const path = require('path');
import http = require('http');
import { Socket } from 'socket.io';
const app = express();
const server = http.createServer(app);
const socketio = require('socket.io')(server);
app.get('/', (req, res) => {
res.send("Node Server is running");
});
server.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
socketio.on("connection", (socket: Socket) => {
console.log(`connect ${socket.id}`);
console.log(`connect ${socket.handshake.url}`);
socket.on("disconnect", () => {
console.log(`disconnect ${socket.id}`);
});
});
Using a tool like Firecamp, I try to establish a connection on ws://localhost:3000, but to no avail. I eventually use the Socket.IO client to connect from a simple web page by running let socket = io(). It seems the only reason this works is because that call connects to the host serving the page by default, as stated here. Running console.log(socket) and looking at the output, I eventually find that the URL inside the engine field is ws://localhost:3000/socket.io/?EIO=4&transport=websocket&sid=qerg3iHm3IKMOjdNAAAA.
My question is why is the URL so complicated rather than simply ws://localhost:3000? And is there no easier way to get the URL instead of having to access it through dev tools?
A socket.io server does not accept generic webSocket connections. It only accepts socket.io connections as socket.io goes through an extra layer of preparation stuff (over http) before establishing the actual webSocket connection. It then also adds a layer on top of the regular webSocket packet format to support some of its features (such as message names).
When using a socket client to connect to a socket.io server in the default configuration, socket.io first makes a few regular http requests to the socket.io server and with those http requests it sends a few parameters. In your URL:
ws://localhost:3000/socket.io/?EIO=4&transport=websocket&sid=qerg3iHm3IKMOjdNAAAA
The path:
/socket.io/
Is the path that the socket.io server is looking for requests on as destined for the socket.io server. Since this is a unique path and not generally used by other requests, this allows you to share an http server between socket.io and other http requests. In fact, this is a common way to deploy a socket.io server (hooking into an http server that you are already using for http requests).
In fact, the path /socket.io/socket.io.js is also served by the socket.io server and that will return the client-side socket.io.js file. So, clients often use this in their HTML files:
<script src="/socket.io/socket.io.js"></script>
as a means of getting the socket.io client code. Again you see the use of the path prefix /socket.io on all socket.io related URLs.
In your original URL, you can see parameters for:
EIO=4 // engine.io protocol version
transport=websocket // desired transport once both sides agree
sid=qerg3iHm3IKMOjdNAAAA // client identifier so the server knows which client this
// is before the actual webSocket connection is established
Once both sides agree that the connection looks OK, then the client will make a webSocket connection to the server. In cases where webSocket connections are blocked (by network equipment that doesn't support them or blocks them), then socket.io will use a form of http polling where it repeatedly "polls" the server asking for any more data and it will attempt to simulate a continuous connection. The client configuration can avoid this http polling and go straight to a webSocket connection if you want, but you would give up the fallback behavior in case continuous webSocket connections are blocked.
And is there no easier way to get the URL instead of having to access it through dev tools?
Not really. This URL is not something you have to know at all. The socket.io client will construct this URL for you. You just specify http://localhost:3000 as the URL you want to connect to and the socket.io client will add the other parameters to it.

Socket.io, server not responding to connection event

I have a managed server at cloudways. I am trying to use socket.io.
client.php:
var socket = io('http://localhost:3000');
console.log(socket);
server.js:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(3000);
io.on('connection', function(socket){
console.log('is connected');
});
When visiting the page, I see two instances of 200 OK in the network section of the console.
The console in the browser also prints the socket variable, which has "connected : true".
However, I DO NOT see "is connected" in the terminal (from server.js), it is just blank.
This site has worked locally, but these problems are appearing when trying to get it to work at Cloudways.
Any ideas?
I have tried switching "localhost" to both the domain name and the IP-address, and I have tried different ports, but 3000 is the only one that will let me start the server.js without error.
EDIT
Cloudways have confirmed that port 3000 should be used.
I have tried changing the url in io() to:
var socket = io('http://my-cloudways-url:3000'); (net::ERR_EMPTY_RESPONSE)
var socket = io('http://www.my-domain.club:3000'); (net::ERR_EMPTY_RESPONSE)
var socket = io('http://ip-adr:3000'); (net::ERR_EMPTY_RESPONSE)
And today I am getting
var socket = io('http://localhost:3000'); (net::ERR_CONNECTION_REFUSED)
I have also tried io.connect(using the same adresses / ports).
Maybe is your php index... Because you are setting the localhost and the port.
I'm not sure about how Cloudway works. But, when we run the server.js, some clouds give some url for access our projects...
In your cloudways try to use the official URL that they given to you access the project:
var socket = io.connect('url.from.cloudway');
For example, I'm using cloud9, and when I execute the server.js, return one url like:
Your code is running: https://demo-some-id.c9.io
And when I'm using socket.io, I need to set in my index the URL parameter inside the IO.
var socket = io('https://demo-some-id.c9.io');
You need to add the client-side socket.io.js version and add the script tag with the path, like:
<script src="js/socket.io.js"></script>
Obs.: Some clouds, you need to set the url in your <script> tag
<script src="https://demo-some-id.c9.io/socket.io/socket.io.js"></script>

Node.js server for Socket.IO explanation?

I have the following code:
express = require('express');
app = express();
http = require('http').createServer(app);
io = require('socket.io')(http);
app.use(express.static(__dirname + '/'));
http.listen(80);
I know it creates a server that clients can connect to and it works. But I don't know what exactly happens. Can you explain in detail?
Also, why things don't work when I forget about Express.js and just use this line:
io = require('socket.io').listen(80);
It appears to listen for connections. However, inside the browser when I go to http://localhost/, nothing happens. My guess is that I don't specify the directory for my app like that:
app.use(express.static(__dirname + '/'));
Is that why I need Express? To specify the directory?
At the client, I use:
socket = io('http://localhost/'); // this
socket = io(); // or this
None of them work with the single line code at the server-side.
Also, why do I need an HTTP server when Socket.IO uses the WebSocket protocol?
When your browser goes to http://localhost/, you need a web server that's going to respond back to the browser with a web page. That's what Express and the express.static() lines were doing. When you remove those, you do indeed have a server listening for webSocket connections on a specific path, but you don't have anything serving web pages. So, when the browser goes to http://localhost/, there's nothing responding back with a plain web page.
Also, why do I need an HTTP server when Socket.IO uses the WebSocket
protocol?
All socket.io connections start with an HTTP request. socket.io is based on the webSocket protocol and all webSocket connections are initiated with an HTTP request. So, to accept a socket.io connection, you need a web server that responds to an HTTP request and you then need a web server that is smart enough to recognize a request for a webSocket connection so it can "upgrade" the protocol from HTTP to webSocket.
For a well written overview of how a webSocket connection is established, see this overview on MDN.
The socket.io infrastructure then runs on top of that webSocket once it is connected.
I know it creates a server that clients can connect to and it works.
But I don't know what exactly happens. Can you explain in detail?
Here's a line-by-line explanation of your code:
express = require('express');
This loads the Express library.
app = express();
This creates an Express app object which can be used as a webServer request handler.
http = require('http').createServer(app);
This creates a web server and passes it the Express app object as the webServer request handler.
io = require('socket.io')(http);
This hooks socket.io into your web server as another request handler so it can see any incoming http requests that are actually the first stage of starting a webSocket/socket.io connection.
app.use(express.static(__dirname + '/'));
This tells Express that if any request is made for a web page that it should look in the __dirname for a file that matches the requested path. If found, it should return that path.
http.listen(80);
This starts the web server listening on port 80.
None of them work with the single line code at the server-side.
Both of those lines of code to create a socket.io connection will work when used properly. You don't say how this code is being run. If you're trying to run this code from a web page that the browser loads from http://localhost/, then I've already explained why that web page won't load if you don't start Express. If you're trying to run those lines of code from a web page loaded some other way, then you're probably having a same-origin security issue were the browser by default won't let you access a domain that is different than the one the web page came from.
You need the express http server to deliver the socket client to the browser.
Express server starts on port 80
Browser connects to express on port 80, the socket.io server component delivers socket client javascript to the browser (http://localhost:80/socket.io/socket.io.js)
Socket client (running in browser) can then connect to socket.io server

Connect to node.js server via web socket (server does not serve pages)

I am attempting to connect to a node.js server via a web socket. The difficulty I am having is that my node server does not serve my web pages. From looking at it I think socket.io assumes that the server will be serving the pages so I can't use 90% of the examples out there (or at least I haven't figured out how to). I am trying to get this simple demo page to connect but am always getting connection refused.
<html>
<head>
<title>Title</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript">
var ws = new WebSocket("ws://my-devbox.local");
</script>
</head>
<body>
<button id="myButton">Click Me Mo Fool!!!</button>
</body>
In my app.js I have the following (with extraneous information omitted)
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function (socket) {
console.log('A new user connected!');
//socket.emit('info', { msg: 'Hello World' });
});
Thanks
There are a couple issues here. First socket.io is not a plain WebSocket. If you use socket.io on the server-side, then you need to use socket.io on the client side. It has its own protocol on top of webSocket so you must use it on both ends of the connection.
Second, socket.io (and any webSocket connection) initiates its connection via an http request. That means it is limited by the same-origin policy (can't connect to origins other than the one that your web page came from). So, you will need to be connecting to a server that has enabled cross origin connections if you want to connect to an origin other than the one serving the web page. Enabling cross origin connections for socket.io is easily done by just doing this on your server:
io.set('origins', '*:*');
More about enabling cross origin requests here: Socket.io + Node.js Cross-Origin Request Blocked and here: how to set socket.io origins to restrict connections to one url

Resources