茄子在线看片免费人成视频,午夜福利精品a在线观看,国产高清自产拍在线观看,久久综合久久狠狠综合

    <s id="ddbnn"></s>
  • <sub id="ddbnn"><ol id="ddbnn"></ol></sub>

  • <legend id="ddbnn"></legend><s id="ddbnn"></s>

    基于node實(shí)現(xiàn)websocket協(xié)議
    來源:易賢網(wǎng) 閱讀:929 次 日期:2016-07-06 15:45:56
    溫馨提示:易賢網(wǎng)小編為您整理了“基于node實(shí)現(xiàn)websocket協(xié)議”,方便廣大網(wǎng)友查閱!

    這篇文章主要介紹了基于node實(shí)現(xiàn)websocket協(xié)議的相關(guān)資料,需要的朋友可以參考下

    一、協(xié)議

    WebSocket是一種基于TCP之上的客戶端與服務(wù)器全雙工通訊的協(xié)議,它在HTML5中被定義,也是新一代webapp的基礎(chǔ)規(guī)范之一。

    它突破了早先的AJAX的限制,關(guān)鍵在于實(shí)時(shí)性,服務(wù)器可以主動(dòng)推送內(nèi)容 到客戶端!可能的應(yīng)用有:多人在線游戲,即時(shí)聊天,實(shí)時(shí)監(jiān)控,遠(yuǎn)程桌面,新聞服務(wù)器等等。

    對(duì)于我自己,當(dāng)前最想嘗試的是canvas+websocket組合起來能做什么。

    二、實(shí)現(xiàn)

    由于握手的過程是一個(gè)標(biāo)準(zhǔn)的HTTP請(qǐng)求,因此 websocket 的實(shí)現(xiàn)有兩種選擇:1)TCP上實(shí)現(xiàn); 2) 現(xiàn)有HTTP軟件上實(shí)現(xiàn)。后者的優(yōu)勢(shì)在于可以共用現(xiàn)有的HTTP服務(wù)器端口,并且不用重新實(shí)現(xiàn)認(rèn)證功能和解析HTTP請(qǐng)求的功能。

    這個(gè)示例中使用的 node 的HTTP模塊。(TCP版及所有文件見 附件)

    1、node服務(wù)器端代碼:

    var http = require('http');

    var url = require('url');

    // var mime = require('mime');

    var crypto = require('crypto');

    var port = 4400;

    var server = http.createServer();

      server.listen(port,function() {

        console.log('server is running on localhost:',port);

        server

        .on('connection',function(s) {

          console.log('on connection ',s);

        })

        .on('request',onrequest)

        .on('upgrade',onupgrade);

      });

    var onrequest = function(req,res) {

      console.log( Object.keys(req) ,req.url,req['upgrade']);

      if( !req.upgrade ){

        // 非upgrade請(qǐng)求選擇:中斷或提供普通網(wǎng)頁(yè)

        res.writeHead(200, { 'content-type': 'text/plain' });

        res.write( 'WebSocket server works!' );

      }

      res.end();

      return;

    };

    var onupgrade = function (req,sock,head) {

      // console.log('方法:',Object.keys(sock));

      if(req.headers.upgrade !== 'WebSocket'){

        console.warn('非法連接');

        sock.end();

        return;

      }

      bind_sock_event(sock);

      try{

        handshake(req,sock,head);

      }catch(e){

        console.error(e);

        sock.end();

      }

    };

    // 包裝將要發(fā)送的幀

    var wrap = function(data) {

      var fa = 0x00, fe = 0xff, data = data.toString()

        len = 2+Buffer.byteLength(data),

        buff = new Buffer(len);

      buff[0] = fa;

      buff.write(data,1);

      buff[len-1] = fe;

      return buff;

    }

    // 解開接收到的幀

    var unwrap = function(data) {

      return data.slice(1,data.length-1);

    }

    var bind_sock_event = function(sock) {

      sock

      .on('data',function(buffer) {

        var data = unwrap(buffer);

        console.log('socket receive data : ',buffer,data,'\n>>> '+data);

        // send('hello html5,'+Date.now())

        sock.emit('send',data);

      })

      .on('close',function() {

        console.log('socket close');

      })

      .on('end',function() {

        console.log('socket end');

      })

      .on('send',function(data) { //自定義事件

        sock.write(wrap(data),'binary');

      })

    };

    var get_part = function(key) {

      var empty  = '',

        spaces = key.replace(/\S/g,empty).length,

        part  = key.replace(/\D/g,empty);

      if(!spaces) throw {message:'Wrong key: '+key,name:'HandshakeError'}

      return get_big_endian(part / spaces);

    }

    var get_big_endian = function(n) { 

      return String.fromCharCode.apply(null,[3,2,1,0].map(function(i) { return n >> 8*i & 0xff }))

    }

    var challenge = function(key1,key2,head) {

      var sum = get_part(key1) + get_part(key2) + head.toString('binary');

      return crypto.createHash('md5').update(sum).digest('binary');

    }

    var handshake = function(req,sock,head) {

      var output = [],h = req.headers, br = '\r\n';

      // header

      output.push(

        'HTTP/1.1 101 WebSocket Protocol Handshake','Upgrade: WebSocket','Connection: Upgrade',

        'Sec-WebSocket-Origin: ' + h.origin,

        'Sec-WebSocket-Location: ws://' + h.host + req.url,

        'Sec-WebSocket-Protocol: my-custom-chat-protocol'+br

      );

      // body

      var c = challenge(h['sec-websocket-key1'],h['sec-websocket-key2'],head);

      output.push(c);

      sock.write(output.join(br),'binary');

    }

    2、瀏覽器客戶端代碼:

    <html>

    <head>

      <title>WebSocket Demo</title>

    </head>

    <style type="text/css">

     textarea{width:400px;height:150px;display:block;overflow-y:scroll;}

     #output{width:600px;height:400px;background:whiteSmoke;padding:1em .5em;color:#000;border:none;}

     button{padding:.2em 1em;}

    </style>

    <link href="layout.css" rel="stylesheet" type="text/css" /> 

    <body>

    <textarea id="output" readonly="readonly"></textarea>

    <br>

    <textarea id="input"></textarea>

    <button id="send">send</button>

    <script type="text/javascript">

    // localhost

    var socket = new WebSocket('ws://192.168.144.131:4400/')

    socket.onopen = function(e) {

      log(e.type);

      socket.send('hello node');

    }

    socket.onclose = function(e) {

      log(e.type);

    }

    socket.onmessage = function(e) {

      log('receive @ '+ new Date().toLocaleTimeString() +'\n'+e.data);

     output.scrollTop = output.scrollHeight

    }

    socket.onclose = function(e) {

      log(e.type);

    }

    socket.addEventListener('close',function() {

      log('a another close event handler..');

    },false);

    // dom

    var id = function(id) {

      return document.getElementById(id);

    }

    var output = id('output'), input = id('input'), send = id('send');

    var log = function(msg) {

      output.textContent += '> '+msg + '\n'

    }

    send.addEventListener('click',function() {

      socket.send(input.value);

    },false);

    </script>

    </body>

    </html>

    三、細(xì)節(jié)

    在 http 協(xié)議之上的 websocket 協(xié)議實(shí)現(xiàn)只有兩步:握手,發(fā)送數(shù)據(jù)。

    1、握手

    握手的過程被稱為 challenge-response。首先客戶端發(fā)起一個(gè)名為Upgrade的HTTP GET請(qǐng)求,服務(wù)器驗(yàn)證此請(qǐng)求,給出101響應(yīng)以表示接受此次協(xié)議升級(jí),握手即完成了。

    chrome inspector美化過的握手信息:

    Request URL:ws://192.168.144.131:4400/pub/chat?q=me

    Request Method:GET

    Status Code:101 WebSocket Protocol Handshake

    Request Headers

    Connection:Upgrade

    Host:192.168.144.131:4400

    Origin:http://localhost:800

    Sec-WebSocket-Key1:p2    G 947T 80  661 jAf2

    Sec-WebSocket-Key2:z Z Q ^326 5 9= 7s1  1 7H4

    Sec-WebSocket-Protocol::my-custom-chat-protocol

    Upgrade:WebSocket

    (Key3):7C:44:56:CA:1F:19:D2:0A

    Response Headers

    Connection:Upgrade

    Sec-WebSocket-Location:ws://192.168.144.131:4400/pub/chat?q=me

    Sec-WebSocket-Origin:http://localhost:800

    Sec-WebSocket-Protocol:my-custom-chat-protocol

    Upgrade:WebSocket

    (Challenge Response):52:DF:2C:F4:50:C2:8E:98:14:B7:7D:09:CF:C8:33:40

    請(qǐng)求頭部分

    Host: websocket服務(wù)器主機(jī)

    Connection: 連接類型

    Upgrade: 協(xié)議升級(jí)類型

    Origin: 訪問來源

    Sec-WebSocket-Protocol: 可選,子協(xié)議名稱,由應(yīng)用自己定義,多個(gè)協(xié)議用空格分割。(*另外一個(gè)僅剩的可選項(xiàng)是cookie)

    Sec-WebSocket-Key1: 安全認(rèn)證key,xhr請(qǐng)求不能偽造'sec-'開頭的請(qǐng)求頭。

    Sec-WebSocket-Key2: 同上

    Key3: 響應(yīng)體內(nèi)容,8字節(jié)隨機(jī)。

    響應(yīng)頭部分

    Sec-WebSocket-Protocol: 必須包含請(qǐng)求的子協(xié)議名

    Sec-WebSocket-Origin: 必須等于請(qǐng)求的來源

    Sec-WebSocket-Location: 必須等于請(qǐng)求的地址

    Challenge Response: 響應(yīng)體內(nèi)容,根據(jù)請(qǐng)求中三個(gè)key計(jì)算得來,16字節(jié)。

    應(yīng)答字符串計(jì)算過程偽代碼:

    part_1 = key1中所有數(shù)字 / key1中空格數(shù)量

    part_2 同上

    sum = big_endian(part_1)+big_endian(part_2)+key3

    challenge_response = md5_digest(sum);

    32位整數(shù)的big_endian計(jì)算策略:

    # 很類似于rgba顏色計(jì)算,從下面的函數(shù)可以看出計(jì)算過程

    var big_endian = function(n) {

      return [3,2,1,0].map(function(i) { return n >> 8*i & 0xff });

    }

    big_endian(0xcc77aaff);

    // -> [204, 119, 170, 255]

    2、發(fā)送數(shù)據(jù)

    WebSocket API的被設(shè)計(jì)成用事件處理數(shù)據(jù),客戶端只要得到事件通知就可以獲取到完整的數(shù)據(jù),而不需要手動(dòng)處理緩沖器。

    這種情況下,每一筆數(shù)據(jù)被稱為一幀。在規(guī)范的定義中,它的頭部必須以0x00開始,尾部屬性以0xff結(jié)束,這樣每一次數(shù)據(jù)發(fā)送至少有兩個(gè)字節(jié)。

    服務(wù)器實(shí)現(xiàn)中,收到數(shù)據(jù)時(shí)要截掉頭尾;而發(fā)送數(shù)據(jù)是要包裝頭尾。格式如下:

    # '你好'的原始二進(jìn)制表示,請(qǐng)求頭和這里都是utf8編碼

    <Buffer e4 bd a0 e5 a5 bd>

    # 包裝后的二進(jìn)制表示。

    <Buffer 00 e4 bd a0 e5 a5 bd ff>

    以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。

    更多信息請(qǐng)查看網(wǎng)絡(luò)編程
    易賢網(wǎng)手機(jī)網(wǎng)站地址:基于node實(shí)現(xiàn)websocket協(xié)議
    由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

    2026上岸·考公考編培訓(xùn)報(bào)班

    • 報(bào)班類型
    • 姓名
    • 手機(jī)號(hào)
    • 驗(yàn)證碼
    關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢 | 簡(jiǎn)要咨詢須知 | 新媒體/短視頻平臺(tái) | 手機(jī)站點(diǎn) | 投訴建議
    工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
    云南網(wǎng)警備案專用圖標(biāo)
    聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號(hào):hfpxwx
    咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
    云南網(wǎng)警報(bào)警專用圖標(biāo)