欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

node.js使用net模塊模擬websocket握手進(jìn)行數(shù)據(jù)傳遞操作示例

本文實(shí)例講述了node.js 使用 net 模塊模擬 websocket 握手進(jìn)行數(shù)據(jù)傳遞操作。分享給大家供大家參考,具體如下:

創(chuàng)新互聯(lián)建站堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的東興網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

websocket 是一種讓瀏覽器與服務(wù)器之間建立持久的連接,并能進(jìn)行雙向數(shù)據(jù)傳輸?shù)囊环N協(xié)議。

websocket 屬性應(yīng)用層協(xié)議,基于tcp傳輸協(xié)議,并復(fù)用http的握手通道。

一、如何進(jìn)行websocket連接。

websocket復(fù)用了http的握手通道,客戶端通過http請求與服務(wù)端進(jìn)行協(xié)商,升級(jí)協(xié)議。協(xié)議升級(jí)完后,后面的數(shù)據(jù)交換則遵照websocket協(xié)議。

1、客戶端申請協(xié)議升級(jí)

Request URL: ws://localhost:8888/
Request Method: GET
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: uR5YP/BMO6M24tAFcmHeXw==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

  • Connection: Upgrade 表示要升級(jí)協(xié)議
  • Upgrade: websocket 表示升級(jí)到websocket協(xié)議
  • Sec-WebSocket-Version: 13 表示websocket的版本
  • Sec-WebSocket-Key 表示websocket的驗(yàn)證,防止惡意的連接,與服務(wù)端響應(yīng)的Sec-WebSocket-Accept是配套。

2、服務(wù)端響應(yīng)協(xié)議升級(jí)

Status Code: 101 Switching Protocols
Connection: Upgrade
Sec-WebSocket-Accept: eS92kXpBNI6fWsCkj6WxH6QeoHs=
Upgrade: websocket

Status Code:101 表示狀態(tài)碼,協(xié)議切換。

Sec-WebSocket-Accept 表示服務(wù)端響應(yīng)的校驗(yàn),與客戶端的Sec-WebSocket-Key是配套的。

3、Sec-WebSocket-Accept是如何計(jì)算的

將 Sec-WebSocket-Key 的值與 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 拼接。

然后通過sha1計(jì)算,再轉(zhuǎn)成base64。

const crypto = require('crypto');
function getSecWebSocketAccept(key) {
  return crypto.createHash('sha1')
    .update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
    .digest('base64');
}
console.log(getSecWebSocketAccept('uR5YP/BMO6M24tAFcmHeXw=='));

4、協(xié)議升級(jí)完后,后續(xù)的數(shù)據(jù)傳輸就需要按websocket協(xié)議來走。

websocket客戶端與服務(wù)端通信的最小單位是 幀,由1個(gè)或多個(gè)幀組成完整的消息。

客戶端:將消息切割成多個(gè)幀,發(fā)送給服務(wù)端。

服務(wù)端:接收到消息幀,將幀重新組裝成完整的消息。

5、數(shù)據(jù)幀的格式

單位是1個(gè)比特位,F(xiàn)IN,PSV1,PSV2,PSV3 占1個(gè)比特位,opcode占4個(gè)比特位。

0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-------+-+-------------+-------------------------------+
|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 ...        |
+---------------------------------------------------------------+

FIN  占1位,用來表示該幀是否是最后一幀,1表示是,0表示不是。

RSV1,RSV2,RSV3  分別占1位,一般情況下全為0,擴(kuò)展使用,值的含義由擴(kuò)展進(jìn)行定義。

opcode 占4位,表示如何解析后面的數(shù)據(jù)載荷(Payload Data)。

%x0 表示一個(gè)延續(xù)幀,opcode為0時(shí),表示數(shù)據(jù)傳輸采用了數(shù)據(jù)分片,當(dāng)前的數(shù)據(jù)幀只是其中一個(gè)數(shù)據(jù)分片。

%x1 表示這是一個(gè)文本幀

%x2 表示這是一個(gè)二進(jìn)制幀

%x3-7 保留的操作代碼,用于定義后續(xù)的非控制幀。

%x8 表示連接斷開

%x9 表示這是一個(gè)ping操作

%xA 表示這是一個(gè)pong操作

%xB-F 保留的操作代碼,用于定義后續(xù)的控制幀。

MASK 占1位,表示是否要對數(shù)據(jù)載荷進(jìn)行掩碼操作。

客戶端向服務(wù)端發(fā)數(shù)據(jù),需要對數(shù)據(jù)進(jìn)行掩碼操作,服務(wù)端向客戶端發(fā)數(shù)據(jù),不需要對數(shù)據(jù)進(jìn)行掩碼操作。

如果Mask為1,則Masking-key中會(huì)定義一個(gè)掩碼鍵,通過該掩碼鍵對數(shù)據(jù)載荷進(jìn)行反掩碼??蛻舳税l(fā)送給服務(wù)端的數(shù)據(jù)幀,MASK都是1。

Payload len 為7位,或7+16位,或7+64位,表示數(shù)據(jù)載荷的長度,單位字節(jié)。

如果Payload len=0~125,表示,數(shù)據(jù)的長度為0~125字節(jié)。

如果Payload len=126,表示,后續(xù)的2個(gè)字節(jié)代表一個(gè)16位的無符號(hào)整數(shù),該整數(shù)表示數(shù)據(jù)的長度。

如果Payload len=127,表示,后續(xù)的8個(gè)字節(jié)代表一個(gè)64位的無符號(hào)整數(shù),該整數(shù)表示數(shù)據(jù)的長度。

如果Payload len占用多個(gè)字節(jié),Payload len的二進(jìn)制表達(dá)采用Big-endian。

Masking-key 占0或32位,客戶端向服務(wù)端發(fā)送數(shù)據(jù)幀,數(shù)據(jù)載荷都進(jìn)行了掩碼操作,Mask為1,且?guī)Я?字節(jié)的Masking-key。如果Mask為0,則沒有Masking-key。

注意數(shù)據(jù)載荷的長度,不包括Masking-key的長度。

6、掩碼的算法

Masking-key掩碼鍵是由客戶端生成的32位隨機(jī)數(shù),掩碼操作不會(huì)影響數(shù)據(jù)載荷的長度。

function unmask(buffer, mask) {
  const length = buffer.length;
  for (var i = 0; i < length; i++) {
    buffer[i] ^= mask[i & 3];
  }
}

7、實(shí)現(xiàn)websocket的握手

const crypto = require('crypto');
const net = require('net');
//計(jì)算websocket校驗(yàn)
function getSecWebSocketAccept(key) {
  return crypto.createHash('sha1')
    .update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
    .digest('base64');
}
//掩碼操作
function unmask(buffer, mask) {
  const length = buffer.length;
  for (var i = 0; i < length; i++) {
    buffer[i] ^= mask[i & 3];
  }
}
//創(chuàng)建一個(gè)tcp服務(wù)器
let server = net.createServer(function (socket) {
  socket.once('data', function (data) {
    data = data.toString();
    //查看請求頭中是否有升級(jí)websocket協(xié)議的頭信息
    if (data.match(/Upgrade: websocket/)) {
      let rows = data.split('\r\n');
      //去掉第一行的請求行
      //去掉請求頭的尾部兩個(gè)空行
      rows = rows.slice(1, -2);
      let headers = {};
      rows.forEach(function (value) {
        let [k, v] = value.split(': ');
        headers[k] = v;
      });
      //判斷websocket的版本
      if (headers['Sec-WebSocket-Version'] == 13) {
        let secWebSocketKey = headers['Sec-WebSocket-Key'];
        //計(jì)算websocket校驗(yàn)
        let secWebSocketAccept = getSecWebSocketAccept(secWebSocketKey);
        //服務(wù)端響應(yīng)的內(nèi)容
        let res = [
          'HTTP/1.1 101 Switching Protocols',
          'Upgrade: websocket',
          `Sec-WebSocket-Accept: ${secWebSocketAccept}`,
          'Connection: Upgrade',
          '\r\n'
        ].join('\r\n');
        //給客戶端發(fā)送響應(yīng)內(nèi)容
        socket.write(res);
        //注意這里不要斷開連接,繼續(xù)監(jiān)聽'data'事件
        socket.on('data', function (buffer) {
          //注意buffer的最小單位是一個(gè)字節(jié)
          //取第一個(gè)字節(jié)的第一位,判斷是否是結(jié)束位
          let fin = (buffer[0] & 0b10000000) === 0b10000000;
          //取第一個(gè)字節(jié)的后四位,得到的一個(gè)是十進(jìn)制數(shù)
          let opcode = buffer[0] & 0b00001111;
          //取第二個(gè)字節(jié)的第一位是否是1,判斷是否掩碼操作
          let mask = buffer[1] & 0b100000000 === 0b100000000;
          //載荷數(shù)據(jù)的長度
          let payloadLength = buffer[1] & 0b01111111;
          //掩碼鍵,占4個(gè)字節(jié)
          let maskingKey = buffer.slice(2, 6);
          //載荷數(shù)據(jù),就是客戶端發(fā)送的實(shí)際數(shù)據(jù)
          let payloadData = buffer.slice(6);
          //對數(shù)據(jù)進(jìn)行解碼處理
          unmask(payloadData, maskingKey);
          //向客戶端響應(yīng)數(shù)據(jù)
          let send = Buffer.alloc(2 + payloadData.length);
          //0b10000000表示發(fā)送結(jié)束
          send[0] = opcode | 0b10000000;
          //載荷數(shù)據(jù)的長度
          send[1] = payloadData.length;
          payloadData.copy(send, 2);
          socket.write(send);
        });
      }
    }
  });
  socket.on('error', function (err) {
    console.log(err);
  });
  socket.on('end', function () {
    console.log('連接結(jié)束');
  });
  socket.on('close', function () {
    console.log('連接關(guān)閉');
  });
});
//監(jiān)聽8888端口
server.listen(8888);

index.html的代碼:

<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
<script>
  var ws = new WebSocket('ws://localhost:8888');
  ws.onopen = function () {
    console.log('連接成功');
    ws.send('你好服務(wù)端');
  };
  ws.onmessage = function (ev) {
    console.log('接收數(shù)據(jù)', ev.data);
  };
  ws.onclose = function () {
    console.log('連接斷開');
  };
</script>
</body>
</html>

希望本文所述對大家node.js程序設(shè)計(jì)有所幫助。

本文題目:node.js使用net模塊模擬websocket握手進(jìn)行數(shù)據(jù)傳遞操作示例
URL標(biāo)題:http://chinadenli.net/article44/jeishe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)網(wǎng)站策劃、響應(yīng)式網(wǎng)站、域名注冊、網(wǎng)站設(shè)計(jì)公司企業(yè)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計(jì)
亚洲午夜精品视频观看| 日本东京热视频一区二区三区| 日本久久中文字幕免费| 精品视频一区二区三区不卡| 亚洲最新av在线观看| 美国女大兵激情豪放视频播放| 欧美黑人暴力猛交精品| 国产精品欧美一区二区三区| 欧美av人人妻av人人爽蜜桃| 青青操日老女人的穴穴| 好吊一区二区三区在线看| 国产户外勾引精品露出一区| 亚洲欧洲在线一区二区三区| 精品一区二区三区三级视频| 国产日产欧美精品视频| 欧美国产日产综合精品| 国产盗摄精品一区二区视频| 中文字幕精品一区二区年下载| 欧美野外在线刺激在线观看| 91久久精品在这里色伊人| 午夜精品麻豆视频91| 日韩人妻毛片中文字幕| 国产女高清在线看免费观看| 99精品国产一区二区青青| 日本不卡在线视频你懂的| 九九热视频经典在线观看| 国产内射在线激情一区| 亚洲一二三四区免费视频| 日韩欧美精品一区二区三区| 亚洲一区二区久久观看| 中文精品人妻一区二区| 97人妻精品免费一区二区| 99久久免费中文字幕| 国产精品白丝久久av| 亚洲午夜福利视频在线| 99免费人成看国产片| 护士又紧又深又湿又爽的视频| 99热在线精品视频观看| 最新日韩精品一推荐日韩精品| 亚洲a级一区二区不卡| 91欧美一区二区三区|