node.js之websocket協議的實現

來源:互聯網
上載者:User

標籤:style   http   color   io   os   ar   for   資料   sp   

websocket已經不是什麼新鮮的東西了,要在node.js上實現也有socket.io這樣好用的第三方模組.但是個人有代碼潔癖,實在是受不了在HTML頁面上多出一行如下代碼:

    <script src=‘http://192.168.0.143:4000/socket.io/socket.io.js‘></script>

而且,項目上要實現的效果是和canvas互動,有些東西還是和socket封裝在一起比較簡單,所以自己踏上了探究websocket的道路.

順便共用下我的勞動成果,還不算完善,因為項目就我一個人在搞...進程有點慢(demo下載後,node啟動nodeCanvas.js)

GitHub:nodeCanvas

因為在github裡面的代碼有注釋,所以我只說一下websocket大概的實現步驟.


Browser端:
 websocket = new WebSocket("ws://" + ip + ":3000/");        //websocket的各種事件        websocket.onopen = function () {            console.log("Connected to WebSocket server.");        };                 websocket.onclose = function () {            console.log("Disconnected");            //zwei.close();        };        websocket.onmessage = function (evt) {            console.log(‘Retrieved data from server: ‘ + evt.data);            //zwei.msg();        };                websocket.onerror = function (evt) {            console.log(‘Error occured: ‘ + evt.data);            //zwei.error();        };                websocket.send("zwei");

上面的是一看就懂的東西有幾個要注意的東西是send發送的東西可以是對象或者數組等,但是不能是多個,只能是一個,而且在server端接收的時候全部都變成十六進位的.


Server端:

server端一開始就比較蛋疼,搞了我將近一個星期,因為之前沒弄個http頭啥的,對這方面瞭解不深也不多....總體上分為2個部分.第一個是協議的升級,讓2端意識到協議升級為websocket.第二個部分就是解碼(後面在介紹).

第一個部分,直接上代碼:

  var key = req.headers[‘sec-websocket-key‘],            steam = new Buffer(0),            resHeaders,            MAGIC_STRING = ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11‘,            websocket;        key = require(‘crypto‘)            .createHash(‘sha1‘)            .update(key + MAGIC_STRING)            .digest(‘base64‘);        resHeaders = [            ‘HTTP/1.1 101 Switching Protocols‘,            ‘Upgrade: websocket‘,            ‘Connection: Upgrade‘,            ‘Sec-WebSocket-Accept: ‘ + key        ];        resHeaders = resHeaders.concat(‘‘, ‘‘).join(‘\r\n‘);        socket.setNoDelay(true);        socket.write(resHeaders);

這部分就是握手的過程。首先用戶端發起一個名為Upgrade的HTTP GET請求,伺服器驗證此請求,給出101響應以表示接受此次協議升級,握手即完成了。

因為在 http 協議之上的 websocket 協議實現只有兩步:握手,發送資料。所以這樣就算建立起了websocket的串連了.

上面代碼各個部分的作用可以自行百度,或者看<<深入淺出Node.js>>,我也是大部分從這本書裡學的


第二部分:

這裡我卡了很久,因為websocket傳送到server端時,資料是十六進位的格式,而且還是加密的,雖然解碼是有規律的不過也折騰了我好久,之後在cnode論壇看到有人寫了一個解碼的,試了下可以,之後就拿他的代碼改了下(畢竟我自己基礎知識不好,對位元運算毫無辦法),這2段代碼還是不錯的,一個解碼,一個加密用於傳送回browser(在browser端接收到server端資料時是自動解碼的所以不用解碼),直接貼上代碼:

//處理掩碼Buffer流(接收)function decodeFrame(frame) {    if (frame.length < 2) {        return null;    }    var counter = 0,        fin_offset = 7,        opcode_offset = parseInt(1111, 2),   //15        mask_offset = 7,        payload_len_offset = parseInt(1111111, 2),   //127        FIN ,        Opcode ,        MASK ,        Payload_len,        buffer,        Masking_key,        i,        j;    FIN = frame[counter] >> fin_offset;    Opcode = frame[counter++] & opcode_offset;    MASK = frame[counter] >> mask_offset;    Payload_len = frame[counter++] & payload_len_offset;    Payload_len === 126 && (Payload_len = frame.readUInt16BE(counter)) && (counter += 2);    Payload_len === 127 && (Payload_len = frame.readUInt32BE(counter + 4)) && (counter += 8);    buffer = new Buffer(Payload_len);    if (MASK) {        Masking_key = frame.slice(counter, counter + 4);        counter += 4;        for (i = 0; i < Payload_len; i++) {            j = i % 4;            buffer[i] = frame[counter + i] ^ Masking_key[j];        }    }    if (frame.length < counter + Payload_len) {        return undefined;    }    frame = frame.slice(counter + Payload_len);    return {        FIN: FIN,        Opcode: Opcode,        MASK: MASK,        Payload_len: Payload_len,        Payload_data: buffer,        frame: frame    };}//處理掩碼Buffer流(發送)function encodeFrame(frame) {    var preBytes = [],        payBytes = new Buffer(frame.Payload_data),        dataLength = payBytes.length;    preBytes.push((frame.FIN << 7) + frame.Opcode);    if (dataLength < 126) {        preBytes.push((frame.MASK << 7) + dataLength);    }    else if (dataLength < Math.pow(2, 16)) {        preBytes.push(            (frame.MASK << 7) + 126,            (dataLength && 0xFF00) >> 8,            dataLength && 0xFF        );    }    else {        preBytes.push(            (frame.MASK << 7) + 127,            0, 0, 0, 0,            (dataLength && 0xFF000000) >> 24,            (dataLength && 0xFF0000) >> 16,            (dataLength && 0xFF00) >> 8,            dataLength && 0xFF        );    }    preBytes = new Buffer(preBytes);    return Buffer.concat([preBytes, payBytes]);}


node.js之websocket協議的實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.