Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js running an http server and web socket server concurrently

I have been trying to implement an HTTP server which receives POST requests from a particular computer. The HTTP server will then extract the message body received and send the body's data to another client, using web sockets.

The code for the HTTP server is the following:

    var http=require('http');


    var server = http.createServer(function(request, response){
        var msgbody='';
        if(request.method == "POST"){
             request.on('data', function(data){
                  msgbody=data;

                  //upon receiving POST request send msgbody to the client using websockets
             });
        }
    }).listen(80);

Could you please provide me with some insight regarding how the web sockets part can be correctly implemented alongside the running HTTP server? The HTTP server and the web socket server need to run on the same port and IP address.

Thank you

like image 756
Questionnaire Avatar asked Jan 24 '26 21:01

Questionnaire


1 Answers

Yes, you can totally do that. For starters, one confusing thing is that the websocket initial request won't come to your data event. It will come to the upgrade event. See node docs for more details.

In your instance, your other server will need to contact this server first with a websocket upgrade request, and that connection will be established. Then when you receive the POST request, you'll need to resend that data across the already-existing websocket request from another server.

Your best bet is absolutely to use an existing library such as ws. You can use this library to attach to an existing http server. See example here. (Example says express, but if you look I believe the ws library is actually attaching to a regular node http server)

If you're curious about exactly how it works, or if your heart is dead set on writing your own websocket server: it is certainly possible. Here's a bare-bones example of what you'd need to do to receive the frames of data from the client. I never actually got around to making the send frames, but this MDN page explains the entire process in detail.

server.on('upgrade', handleWS);

function handleWS(request, socket, buf) {
    var key = getHeader(request, 'Sec-WebSocket-Key');
    var magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
    var shasum = crypto.createHash('sha1');
    shasum.update(key + magic);
    var akey = shasum.digest('base64');
    var resp = ['HTTP/1.1 101 Switching Protocols',
        'Upgrade: websocket',
        'Connection: Upgrade',
        'Sec-WebSocket-Accept: ' + akey, '', ''].join('\r\n');
    console.log(key, resp);
    socket.write(resp);
    var inbuff = '';
    socket.on('data', function (buf) {
        var fin = buf.readUInt8(0) >> 7;
        var opcode = buf.readUInt8(0) & 15; //0=cont, 1=text, 2=binary
        var mask = buf.readUInt8(1) >> 7, bmask;
        var len = buf.readUInt8(1) & 127;
        var i = 2;
        if (len === 126) { len = buf.readUInt16BE(i); i += 2; }
        else if (len === 127) {
            len = (buf.readUInt32BE(i) << 32) + buf.readUInt32BE(6);
            i += 8;
        }
        if (mask) { bmask = buf.slice(i, i + 4); i += 4; }
        data = buf.slice(i, i + len);
        if (mask) for (var j = 0; j < data.length; j++) 
            data[j] = data[j] ^ bmask[j % 4];
        if (opcode === 1) data = data.toString('utf8');
        // todo: handle fragmentation
        console.log(fin, opcode, mask, len, data);
    })
}
function getHeader(req, key) {
    var keyl = key.toLowerCase()
    for (var k in req.headers) if (k.toLowerCase() === keyl) return req.headers[k];
    return '';
}
like image 62
David784 Avatar answered Jan 26 '26 14:01

David784