18

I'm trying to create something like chat using nodejs. I'm a newbie in nodejs and i want to create it without socket.io (i want to learn how it works). Here is the code i'm using.

var http = require('http');
var net = require('net');


var server = http.createServer(function(req,res){

    res.writeHead(200,{'content-type' : 'text/html'});
    res.write('<a href="./lol/">lol</a><br>');
    res.end('hello world: '+req.url);



    var client = new net.Socket();
    client.connect('7001', '127.0.0.1', function() {

        console.log('CONNECTED TO: ');
        // Write a message to the socket as soon as the client is connected, the server will receive it as message from the client 
        client.write('I am Chuck Norris!');

    });

    // Add a 'data' event handler for the client socket
    // data is what the server sent to this socket
    client.on('data', function(data) {

        console.log('DATA: ' + data);
        // Close the client socket completely
        client.destroy();

    });

    // Add a 'close' event handler for the client socket
    client.on('close', function() {
        console.log('Connection closed');
    });
    //req.

});
server.listen(7000);


require('net').createServer(function (socket) {
    console.log("connected");

    socket.on('data', function (data) {
        console.log(data.toString());
    });
}).listen(7001);

And all works fine, (i think). When i open localhost:7000 i'm getting in node CMD messages about "CONNECTED TO:" and "connected" and "I am Chack Norris". After that i'm trying to write in the browser console:

var conn = new WebSocket('ws://localhost:7001/');

Also no errors, but when i try this line:

conn.send('lol');

I'm getting an error: "Uncaught DOMException: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.(…)"

And after some time i get one more error: "WebSocket connection to 'ws://localhost:7001/' failed: WebSocket opening handshake timed out"

maybe this code is wrong, but i have tried everything that i found through google. Can someone help me with this?

Mohamed Osman
  • 136
  • 2
  • 16
Illia Moroz
  • 343
  • 1
  • 2
  • 13

2 Answers2

30

If you want to create your own webSocket server that can receive webSocket connections from the browser, you will have to implement the webSocket protocol on your server. It is not just a simple socket connection. It has a startup sequence that starts as an HTTP connection that is then "upgraded" to the webSocket protocol, including an exchange of security info and then there is a webSocket framing format for all data sent over the webSocket. You don't just send plain text over a webSocket.

You can see what the webSocket protocol looks like here: Writing Websocket Servers. Unless you really want to make your own webSocket server just for learning purposes, I'd really suggest you get an existing module that has done all the nitty gritty protocol work for you.

The socket.io library is then built on top of the webSocket protocol, adding additional features and message format on top of that.

To give you an idea how a webSocket connects, here's a typical connection sequence:

Browser sends connect request:

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

Server responds:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Then, both sides switch to the webSocket protocol which has a data framing format like this:

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

Then, in addition, there are ping and pong packets for keep-alive tests and there is a scheme for large packets and fragmentation and client/server can negotiate a sub-protocol.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks! That was very helpfull! – Illia Moroz Sep 29 '15 at 09:29
  • 2
    Thanks @jfriend00, I spent much time between nodejs net module, and http upgrade to avoid using 3rd party libraries, you answer is convincing me to stop now, and start using ready socket library, thanks. – Hasan A Yousef Dec 01 '15 at 08:34
  • @jfriend00, that was a marvelous answer. However, one thing didn't gel for me. When I connect to [WebSocket.org](https://www.websocket.org/echo.html) for an echo-test from a client, I never send an HTTP `GET` to their server. All I do is open a WebSocket with `new WebSocket('wss://echo.websocket.org')`. My question: **is it only on the server that needs to implement the upgrade above? Is there an HTTP Route set up for `GET /chat`?** Also, can you elaborate on the `Sec-WebSocket-Accept` header value? That doesn't look like a static Base-64 string to me. – Cody Sep 10 '19 at 07:19
  • 2
    @Cody - `new WebSocket('wss://echo.websocket.org')` does the http request for you. It carries out the whole webSocket protocol for you including that initial http request. You generally wouldn't implement your own webSocket server, but you'd use a library that hooks into your existing http server, listening for incoming requests with the `upgrade: websocket` header set and then takes over that request from there on. – jfriend00 Sep 10 '19 at 07:21
  • Thx, @jfriend00. So it sounds like there's just a route/controller at `GET /chat` that responds with such headers but there's not too much to deal with afterword beside heartbeat/keep-alive implementations. I need not worry about parsing packets after that, correct? My curiosity drives me to ask how I should expect to receive & handle messages though. Any info you can provide on that? (BTW, totally appreciate all the knowledge you have on this stuff; super helpful!) – Cody Sep 12 '19 at 05:48
  • 1
    @cody - The websocket implementation built into browsers handles all the packet manipulation and protocol stuff for you. You just send data and receive data in whatever format you want to send/receive it. webSocket itself does not have any specific keep alive or heartbeat so if you want that, you implement it yourself on top of the webSocket protocol by sending your own data every so often. – jfriend00 Sep 12 '19 at 21:40
-1

As suggested above, better not write your own socket server unless you really need/want to.

A great socket server with a simple interface is ws https://github.com/websockets/ws

With just a few lines you can start sending and receiving messages server-side.

Meanwhile, on the client-side you don't need a library, just:

new WebSocket('wss//echo.websocket.org')

read more

Boris Yakubchik
  • 3,861
  • 3
  • 34
  • 41