21

I am trying to enable tcp, http and websocket.io communication on the same port. I started out with the tcp server (part above //// line), it worked. Then I ran the echo server example found on websocket.io (part below //// line), it also worked. But when I try to merge them together, tcp doesn't work anymore.

SO, is it possible to enable tcp, http and websockets all using the same port? Or do I have to listen on another port for tcp connections?

var net = require('net');
var http = require('http');
var wsio = require('websocket.io');

var conn = [];

var server = net.createServer(function(client) {//'connection' listener
    var info = {
        remote : client.remoteAddress + ':' + client.remotePort
    };
    var i = conn.push(info) - 1;
    console.log('[conn] ' + conn[i].remote);

    client.on('end', function() {
        console.log('[disc] ' + conn[i].remote);
    });

    client.on('data', function(msg) {
        console.log('[data] ' + conn[i].remote + ' ' + msg.toString());
    });

    client.write('hello\r\n');
});

server.listen(8080);

///////////////////////////////////////////////////////////

var hs = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-Type' : 'text/html'
    });
    res.end(['<script>', "var ws = new WebSocket('ws://127.0.0.1:8080');", 'ws.onmessage = function (data) { ws.send(data); };', '</script>'].join(''));
});

hs.listen(server);

var ws = wsio.attach(hs);
var i = 0, last;

ws.on('connection', function(client) {

    var id = ++i, last

    console.log('Client %d connected', id);

    function ping() {
        client.send('ping!');
        if (last)
            console.log('Latency for client %d: %d ', id, Date.now() - last);
        last = Date.now();
    };

    ping();
    client.on('message', ping);

});
kanaka
  • 70,845
  • 23
  • 144
  • 140
Some Noob Student
  • 14,186
  • 13
  • 65
  • 103
  • 1
    HTTP typically runs on top of TCP. What do you mean by HTTP and TCP? – John Dvorak Dec 09 '12 at 19:46
  • That's why I'm in doubt. My server needs to communicate with websockets via browsers and TCP connections via mobile apps. Thus I need both protocols. – Some Noob Student Dec 09 '12 at 19:48
  • Perhaps you could listen as raw TCP and if you detect HTTP, forward to the other handler manually. Likewise, if you detect WS from the HTTP server (WS starts as HTTP), delegate again. – John Dvorak Dec 09 '12 at 19:51
  • Normally you should use HTTP for all and distinguish by URL, or run the raw TCP on a different port. – John Dvorak Dec 09 '12 at 19:52
  • note that an HTTP stream usually compresses very well with GZIP and you don't gain much by using raw sockets (having one duplex TCP connection instead of two simplex connections is not really a win). You do get message serialization (unless WS is duplex as well). – John Dvorak Dec 09 '12 at 19:56

3 Answers3

34

You can have multiple different protocols handled by the same port but there are some caveats:

  • There must be some way for the server to detect (or negotiate) the protocol that the client wishes to speak. You can think of separate ports as the normal way of detecting the protocol the client wishes to speak.

  • Only one server process can be actually listening on the port. This server might only serve the purpose of detecting the type of protocol and then forwarding to multiple other servers, but each port is owned by a single server process.

  • You can't support multiple protocols where the server speaks first (because there is no way to detect the protocol of the client). You can support a single server-first protocol with multiple client-first protocols (by adding a short delay after accept to see if the client will send data), but that's a bit wonky.

An explicit design goal of the WebSocket protocol was to allow WebSocket and HTTP protocols to share the same server port. The initial WebSocket handshake is an HTTP compatible upgrade request.

The websockify server/bridge is an example of a server that can speak 5 different protocols on the same port: HTTP, HTTPS (encrypted HTTP), WS (WebSockets), WSS (encrypted WebSockets), and Flash policy response. The server peeks at the first character of the incoming request to determine if it is TLS encrypted (HTTPS, or WSS) or whether it begins with "<" (Flash policy request). If it is a Flash policy request, then it reads the request, responds and closes the connection. Otherwise, it reads the HTTP handshake (either encrypted or not) and the Connection and Upgrade headers determine whether it is a WebSocket request or a plain HTTP request.

Disclaimer: I made websockify

activedecay
  • 10,129
  • 5
  • 47
  • 71
kanaka
  • 70,845
  • 23
  • 144
  • 140
  • @kanaka : how many clients can connect to a single port ? I want to know that at a time how many web socket connections a Java web app can handle ? On each web socket request from client do we need a diff port on server ? – Dax Joshi Oct 15 '15 at 11:15
  • 2
    @DaxJoshi that's probable better as a separate question. It also really doesn't have to do anything with Websockets. The server port where TCP connections are _accepted_ can handle a lot of connections. You don't a separate server port for each client. In the websockify case, if you are want different clients to connect to different targets via websockify, then you should look at the [TokenFile plugin/target config](https://github.com/kanaka/websockify/wiki/Token-based-target-selection) functionality of websockify. – kanaka Oct 15 '15 at 17:15
0

Short answer - NO, you can't have different TCP/HTTP/Websocket servers running on the same port.

Longish answer - Both websockets and HTTP work on top of TCP. So you can think of a http server or websocket server as a custom TCP server (with some state mgmt and protocol specific encoding/decoding). It is not possible to have multiple sockets bind to the same port/protocol pair on a machine and so the first one will win and the following ones will get socket bind exceptions.

dhruv chopra
  • 490
  • 3
  • 11
  • No, you cannot have multiple "servers" or services bound to the same port, but you can certainly have a single service that can handle both HTTP and Websocket requests. – curiouser Apr 06 '20 at 12:53
0

Nginx allows you to run http and websocket on the same port, and it forwards to the correct appliaction. See this article.

General Grievance
  • 4,555
  • 31
  • 31
  • 45