I am a beginner in node.js. Here is what I am trying to do using express + https.
- node.js https server on port 443
- C client connects to sever
- Mobile client connects to server and does GET
- node.js server sends GET request to C client and sends response back to mobile device
While sending GET request from node.js to C client, I could not get hold of TLS socket instance.
The node.js https documentation says
Class: https.Server#
This class is a subclass of tls.Server and emits events same as http.Server. See
http.Server for more information.
after storing socket
https.on('connection', function(socket) {
global_https_obj[0]=socket;
});
and doing global_https_obj[0].write("DEADBEEF") .. it sends plain text traffic without SSL header and client blocks on SSL_read() [openSSL][ C client does receives GET request but openSSL gives decryption alert and fails to decrypt it ]
It seems TLS socket is accessible through secureConnection event and is not emitted by https.
guys is there any way get hold of TLS socket? or is it possible to add secureConnection event listener in https?
Related
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.
I am running a little website using IIS 7.5 on Windows Server 2008 R2.
I've got a node.js application too running on port 3000.
Http calls from the website (client browser) are reverse proxied from http://example.com/node/whatever to http://localhost:3000/whatever. Everything works fine so far.
The problem is when i try to use socket.io.
I am receiving:
WebSocket connection to 'ws://example.com/socket.io/?EIO=3&transport=websocket&sid=adb9WRpoMFYRoS0vAAAB'
failed: Error during WebSocket handshake: Unexpected response code: 502
I am pretty sure, if i am not wrong, that:
It does forward the initial request to my server as the initial request to a websocket server is a standard HTTP request (with some additional headers). IIS does know about that and simply forwards the request. However, upon receiving the websocket request the websocket server sends a 101 response and switch into websocket mode. IIS does not understand the websocket traffic and it is not able to proxy that.
Is there a trick or solution to configure the reverse proxy for the ws:// adresses?
I'll expand a bit on my comments.
As far as I understand, you have several options :
bypass the reverse proxy after the connection (ugly hack if you ask me) : http://www.guyellisrocks.com/2014/06/using-websockets-when-your-reverse.html
upgrade to a more recent version that support native websockets everse-proxying. See this related serverfault thread and this technet features announcement
force socket-io to not to upgrade to websockets Socket.io (post v1.0) should already handle that I think, that is it should stay in comet/long-polling and not upgrade if the Websocket handshake doesn't work. But you can force it manually anyway.
So, which version of socket.io are you using ? See the docs for allowed transports (extract below) :
io.enable('browser client minification'); // send minified client
io.enable('browser client etag'); // apply etag caching logic based on version number
io.enable('browser client gzip'); // gzip the file
io.set('log level', 1); // reduce logging
// enable all transports (optional if you want flashsocket support, please note that some hosting
// providers do not allow you to create servers that listen on a port different than 80 or their
// default port)
io.set('transports', [
'websocket'
, 'flashsocket'
, 'htmlfile'
, 'xhr-polling'
, 'jsonp-polling'
]);
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/
There is a way to manage the socket.io creation at Server Side?, Currently, I couldn't found any doc, Only found in relation with the socket is created per request from a client "io.connect(server)".
The current flow work OK:
Set Socket.io (at Node.js) at SERVER:PORT
Client connect to SERVER
using io.connect(SERVER:PORT)
I wonder if it is possible ? Trying to do:
Set Socket.io (at Node.js) at SERVER:PORT
Recieved a POST (REST) - Server side
Create/Open Socket.io a server side.
At response of Post send the id?
the clien open a socke.io
Sent to client socket.id to client as
So Far, looking in deep on the code and doc, I found that socket.io support namespaces, so I used this in order to manage client connection id.
at server.js
var app = express();
var server = require('http').createServer(app),
io = require('socket.io').listen(server,{ log: false });
// Rest New Process
function generateNameSpaceWs (responce, request) {
io.of("/" + id).on('connection', handler);
response.send(id);
}
app.post("/newWS", function (res, req) {
return generateNameSpaceWs(res, req);
}
at Client.js
function makeWS(){
var ws, c = new XMLHttpRequest();
c.open("GET", url, false);
c.send();
if (c.status == 200){
id = JSON.parse(c.responseText);
ws = new io.connect("server/" + id)
}
So far you are doing right, if I understand your question correctly, you are trying to authenticate connection via POST, so that user can only connect to server via socket if server responds to ID. This is a roundabout way. Use the socket instead of POST.
Socket server has to be running already, and accepts connection via io.sockets.on('connection'), at server you can choose whether to accept it or reject it ,do socket.disconnect('unauthorized') to close connection from server.
I would you suggest you do this :
Set Socket.io (at Node.js) at SERVER:PORT
Client connect to SERVER using io.connect(SERVER:PORT)
Send what you are sending in POST over socket.
Authenticate/Process on io.sockets.on('connection', function(socket) at server.
Close socket if unathorized.
Send back ID data to client.
This doesn't seem possible -- while the official documentation for socket.io is lacking, the documentation for the net module indicates that the only way to create a socket is to initiate it server side.
However, you can still achieve the desired effect by creating an id for the socket on the server to associate with the socket. That is,
Set Socket.io (at Node.js) at SERVER:PORT
Recieved POST (REST) - Server side
Create id (Note:This could be done before step 2)
At response of Post send the id!
Client connect to SERVER
using io.connect(SERVER:PORT)
The client sends the id to the server using something like
socket.emit("set_id",id)
The server recieves the id and associates it with the socket using something like
socket.on("set_id",function(id){
socket.set("id",id)
}
Now you can reference the socket using the id that you created!
Good luck!
I am currently experiencing with Websockets.
By reviewing some active projects/implementations like einaros/ws (and others as well) I found out that they implement the server their own. Instead of using the node net module which provides a tcp server. Is there a reason for this approach?
https://github.com/einaros/ws/blob/master/lib/WebSocketServer.js
Regards
Update:
var server = net.createServer(function(c) {
c.on('data', function(data) {
// data is a websocket fragment which has to get parsed
});
// transformToSingleUtfFragment is building a websocket valid
// byte fragment which contains hello as application payload
// and sets the right flags so the receiver knows we have a single text fragment
c.write(transformToSingleUtfFragment('hello'));
c.pipe(c);
});
server.listen(8124, function() { //'listening' listener
console.log('server bound');
});
WebSocket's a a protocol layered on top of normal HTTP.
How it works is basically that the browser sends a UPGRADE HTTP request and then makes use of the HTTP 1.1 keep alive functionality to keep the underlying TCP socket of the HTTP connection open.
The data is then send via the WebSocket Protocol (Rather large RFC behind the link), which itself is built on top of TCP.
Since the HTTP part is required, and you need to re-use the TCP connection from that one, it makes sense to go with the normal HTTP server instead of net.Server. Otherwise you'd had to implement the HTTP handling part yourself.
Implementing the WebSocket Protocol needs to be done in either case, and since any HTTP connection can be upgraded, you can, in theory, simply connect your WebSocket "server" to the normal HTTP Server on Port 80 and thus handle both normal HTTP requests and WebSockets on the same port.