Solving Socket.IO socket undefined on connection from Arduino? - node.js

I'm trying to connect to socket.io from arduino. The service works from the browser, but if I try to connect from the arduino, when I look in the node log I created via console.log when a connection happens, the socket is undefined, but picks up the connection. Below is the protocol switching request, which returns a 404 not found, but socket.io does register a connection but doesn't define the socket.
client.print(F("GET /socket.io/1/websocket/"));
client.print(sid);
client.println(F(" HTTP/1.1"));
client.print(F("Host: "));
client.print(hostname);
client.fastrprint(F(":"));
char portBuffer[10];
itoa(port, portBuffer, 10);
client.fastrprint(portBuffer);
client.print(F("Sec-WebSocket-Key: ")); //dGhlIHNhbXBsZSBub25jZQ==
client.print(F("dGhlIHNhbXBsZSBub25jZQ=="));
client.println(F("Origin: ArduinoSocketIOClient"));
client.println(F("Sec-WebSocket-Protocol: chat, superchat"));
client.println(F("Sec-WebSocket-Version: 13"));
client.println(F("Upgrade: websocket"));
client.println(F("Connection: Upgrade\r\n"));
I was thinking maybe I formed the request incorrectly, but I can't find any information for the socket.io protocol switching request so I don't know what to change. What I have done is loosely based on what I read in web socket protocol stand.

Related

Using Socket.io with Sequelize

I am trying to use Socket.io and Sequelize to create a chat app. Socket.io will handle the socket to allow for instant messaging. Sequelize will handle storing the messages so when you refresh the screen you still have your messages.
What is happening is that on localhost my socket works, but it does not send the messages to the database. When I put it onto Heroku, my database worked, but it does not use the sockets.
My socket is located in app.js and my database route is located in routes/messages.js.
I have been working on this bug for a while now and I have been trying to get help with it. I think the best way to share this is with my markdown I created detailing my efforts to fix my bug that can be found at here. My repo for this can be found here.
There are a few different parts that you need to distinguish:
the HTTP server, in your code represented by the variable http
the Express app, represented by app
the Socket.IO server, represented by io
a Socket.IO (client) connection (see below)
The HTTP server directs "normal" HTTP requests to the Express app, which will handle them according to the middleware and routes that are set up. A router handler gets called with (at least) two arguments, generally called req and res, to represent the (incoming) HTTP request and the (outgoing) HTTP response.
The Socket.IO server gets to handle specific Socket.IO requests, which get sent to the server by the Socket.IO client (running in the browser). When such a client sets up a connection with the server, the connection event gets triggered on the server. Any handlers for this event will get passed an argument, generally called socket, that represents the (bidirectional) connection with that client.
That Socket.IO connection can receive messages (sent from the client running in the browser), which trigger events on the socket. You can install a handler to listen for particular messages (like "chat message"), which will receive, as argument, the data that was sent to it by the client.
The issue in your code seems to be with setting up everything to handle those chat messages. The correct setup order would be:
listen on the Socket.IO server for connection events
when such an event is received, add a listener for the chat message event on the connection
when such an event is received, write the data to the database.
In code:
// Listen for new client connections.
io.on('connection', function(socket) {
// Listen for the client to send a _"chat message"_ message.
socket.on('chat message', function(data) {
// Store the data in the database.
models.Messages.create({
message : data.message,
username : data.username
});
});
});
As you can see, req and res aren't available inside of those Socket.IO event handlers, because those are only used for normal HTTP requests.
Also, as opposed to HTTP, you don't necessarily have to send anything back to the client when you have received a message, so I left that part out. The handler above only writes the message data to the database (it also doesn't check for, or handle, errors, which eventually you should add).

Socket.io connection event not fired on server

I am trying to build a command-line chat room using Node.js and Socket.io.
This is my server-side code so far, I have tried this with both http initialisations (with express, like on the official website's tutorial, and without it):
#app = require('express')()
#http = require('http').Server(app)
http = require('http').createServer()
io = require('socket.io')(http)
io.sockets.on 'connect', (socket) ->
console.log 'a user connected'
http.listen 3000, () ->
console.log 'listening on *:3000'
I start this with nodejs server.js, the "Listening on" is showing up.
If I run lsof -i tcp:3000, the server.js process shows up.
However, when I start this client-side code:
socket = require('socket.io-client')('localhost:3000', {})
socket.on 'connect', (socket) ->
console.log "Connected"
No luck... When I run nodejs client.js, neither "connect" events, from server nor client, are fired!
My questions are :
- What am I doing wrong?
- Is it necessary to start a HTTP server to use it? Sockets are on the transport layer, right? So in theory I don't need a HTTP protocol to trade messages.
If this is a server to server connection and you're only making a socket.io connection (not also setting it up for regular HTTP connections), then this code shows the simple way for just a socket.io connection:
Listening socket.io-only server
// Load the library and initialize a server on port 3000
// This will create an underlying HTTP server, start it and bind socket.io to it
const io = require('socket.io')(3000);
// listen for incoming client connections and log connect and disconnect events
io.on('connection', function (socket) {
console.log("socket.io connect: ", socket.id);
socket.on('disconnect', function() {
console.log("socket.io disconnect: ", socket.id);
});
});
Node.js socket.io client - connects to another socket.io server
// load the client-side library
const io = require('socket.io-client');
// connect to a server and port
const socket = io('http://localhost:3000');
// listen for successful connection to the server
socket.on('connect', function() {
console.log("socket.io connection: ", socket.id);
});
This code works on my computer. I can run two separate node.js apps on the same host and they can talk to one another and both see the connect and disconnect events.
Some Explaining
The socket.io protocol is initiated by making an HTTP connection to an HTTP server. So, anytime you have a socket.io connection, there is an HTTP server listening somewhere. That HTTP connection is initially sent with some special headers that indicate to the server that this is a request to "upgrade" to the webSocket protocol and some additional security info is included.
This is pretty great reference on how a webSocket connection is initially established. It will show you step by step what happens.
Once both sides agree on the "upgrade" in protocol, then the protocol is switched to webSocket (socket.io is then an additional protocol layer on top of the base webSocket protocol, but the connection is all established at the HTTP/webSocket level). Once the upgrade is agreed upon, the exact same TCP connection that was originally the incoming HTTP connection is repurposed and becomes the webSocket/socket.io connection.
With the socket.io server-side library, you can either create the HTTP server yourself and then pass that to socket.io or you can have socket.io just create one for you. If you're only using socket.io on this server and not also sharing using http server for regular http requests, then you can go either way. The minimal code example above, just lets socket.io create the http server for you transparently and then socket.io binds to it. If you are also fielding regular web requests from the http server, then you would typically create the http server first and then pass it to socket.io so socket.io could bind to the http server you already have.
Then, keep in mind that socket.io is using the webSocket transport. It's just some additional packet structure on top of the webSocket transport. It would akin to agreeing to send JSON across an HTTP connection. HTTP is the host transport and underlying data format. Both sides then agree to format some data in JSON format and send it across HTTP. The socket.io message format sits on top of webSocket in that way.
Your Questions
Is it necessary to start a HTTP server to use it?
Yes, an HTTP server must exist somewhere because all socket.io connections start with an HTTP request to an HTTP server.
Sockets are on the transport layer, right?
The initial connection protocol stack works like this:
TCP <- HTTP protocol
Then, after the protocol upgrade:
TCP <- webSocket <- socket.io
So after the protocol upgrade from HTTP to the webSocket transport, you then have socket.io packet format sitting on top of the webSocket format sitting on top of TCP.
So in theory I don't need a HTTP protocol to trade messages.
No, that is not correct. All connections are initially established with HTTP. Once the upgrade happens to the webSocket transport, HTTP is no longer used.

How to detect the socket server authorization failure on client side in socket.io?

I want to connect an js socket client to socket.io server using
socket = io.connect(). But on server side i m using io.use() method to check whether this socket connection contains cookies or not. I restrict the request on socket server to make connection if socket initial handshake does not contain cookies. by passing
next(new Error("Authentication Error")). But i m not able to catch this error on client side. I want to notify the client of invalid login session and login again.
Thanks
Thanks Andrey... I got success with
socket.on("error", function()
{
//function to perform on occurance of authorisation failure
})
I think you need to listen on connect_error:
socket.on('connection_error', function(data) {
// data here should be an Error object sent by server
});
The documentation is awful, but here is a little hint (found here):
Errors passed to middleware callbacks are sent as special error
packets to clients.

can I use socket.io-client to connect to a standard websocket?

Trying to use socket.io-client to connect to a websocket server that is written in Go. I've successfully connected using the node WebSocket library (npm). So the working Websocket code looks like:
goSocketPort = 6060
url = "ws://localhost:#{goSocketPort}/streamresults/"
ws = new WebSocket(url)
ws.on('open', ->
log "socket opened"
)
ws.on('message', (message) ->
console.log('received: %s', message)
#log "Socket message: #{JSON.stringify message}"
)
Pretty easy and it works -- the socket on the other end sends messages on a set frequency. But I initially tried with socket.io-client (npm) and just couldn't get it to go. It certainly lists websocket as its first-preference transport, but damn if I can get it to connect:
socket = ioClient.connect("#{url}", {port: goSocketPort, transports: ['xhr-polling', 'websocket']})
socket.on("connect", (r) ->
log "connected to #{url}"
)
The connection never happens, so none of the on events are fired and the code exits right away. I've tried: leaving the port off the url and adding it in the options, leaving off the transports option (which means "all" according to the docs) and using an http url. Is socket-io.client not capable of connecting to a "standard" websocket?
Based on our chat, it looks like you were misled by this quote:
The socket.io client is basically a simple HTTP Socket interface implementation. It looks similar to WebSocket while providing additional features and leveraging other transports when WebSocket is not supported by the user's browser.
What this means is that it looks similar to WebSocket from the perspective of client/server code that interacts with the Socket.io client/server. However, the network traffic looks very different from a simple WebSocket - there's an initial handshake in addition to a more robust protocol built on top of WebSocket once that's connected. The handshake is described here and the message protocol here (both are links to the Socket.IO protocol spec).
If you're writing a WebSocket server, you're better off just using the bare WebSocket interface rather than the Socket.io client, unless you intend to implement all of the Socket.io protocol.
Not sure if this was the case at the time, but socket.io's website now states this directly in the docs.
Although Socket.IO indeed uses WebSocket as a transport when possible,
it adds additional metadata to each packet. That is why a WebSocket
client will not be able to successfully connect to a Socket.IO server,
and a Socket.IO client will not be able to connect to a plain
WebSocket server either.
https://socket.io/docs/

socket.io client connection cannot be made on the 2nd time

Currently, I am implementing an API using nodejs express, then it needs to connect to socket.io and send event.
The API is located in socket.io-client (client), and it connects to socket.io (server)
1st API call: success
The connection is made for the 1st call of the API, message is sent and socket can be disconnected, with the 'disconnect' callback is invoked both on client and server side.
2nd API call: failure
When the API is invoked the 2nd time, the connection to server cannot be made, 'client' callback on client side is not called.
3rd API call: success
Then I tried to restart the client side, keeping other things unchanged. The API is called again, and the connection to socket.io is made successfully and everything is fine.
Can anyone explain the logistics behind this?
Updated
client.js
App.getByUserId(message.to_id, function(error, app) {
var socket = io.connect('http://127.0.0.1:9002');
socket.on('connect', function(){
console.log("client connect socket id:" + socket.id);
console.log("appkey:" + app.private_token);
socket.emit('appkey.check',{appkey: app.private_token, uuid: message.to_id.uuid}, function(data){
socket.emit("forceDisconnect");
socket = null;
});
});
You just hit one of Socket.IO's many "features" or "bugs" depending how you see this. Socket.IO tries to be smart and re-use connections (which causes a lot of connection issues actually) The way around this is use the force new connection option in your io.connect:
io.connect('http://127.0.0.1:9002', { 'force new connection': true });
What you could also do is use https://github.com/primus/primus which wraps Socket.IO if you use the socket.io transformer. Internally, it completely removes the use of the io.connect and uses the much more lower level io.Socket constructor to create more stable connections that you would get with a stock socket.io.
With socket 1.0+, you have to use this for forcing new connection.
io.connect(SERVER_IP, { 'forceNew': true });

Resources