Websocket introduction and simple implementation

Node

const net = require('net'); 
const crypto = require('crypto'); const map = new Set(); Net.createserver ((socket)=>{// Start transmitting data after TCP handshake const header = {}; socket.once('data',(data)=>{
    let tmpHeader = data.toString().split('\r\n');
    tmpHeader.shift();
    tmpHeader.forEach(item=>{
      if(item){
        let index = item.indexOf(':'); const key = item.substr(0,index); const value = item.substr(index+1); header[key.trim().toLocaleLowerCase()] = value.trim(); }})if(header.upgrade.toLocaleLowerCase()==='websocket'&&header['sec-websocket-version'] = ='13'){
      const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
      const socketkey = header['sec-websocket-key']
      const hash = crypto.createHash('sha1') // Create a hash object with the signature algorithm sha1 hash.update('${socketkey}${GUID}'// Connect key to GUID, update tohash
      const result = hash.digest('base64'// Base64 const responseHeader = 'HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-Websocket-Accept:${result}\r\n\r\n`;
      socket.write(responseHeader)
      map.add(socket);
      socket.on('data',(d)=>{
        const decodedData = decodeWsFrame(d);
          if (decodedData.opcode === 8) {
            //frame-opcode-control    = %x8 ; connection close
            console.log('close'); Socket.end () // Disconnect from the client map.delete(socket); }else {
            map.forEach(w=>{
              if(w! =socket){ w.write(encodeWsFrame({ payloadData: decodedData.payloadData ||"" }))
              }
            })
          }
        })

    }
  })
}).listen(8083);


function decodeWsFrame(data) {
  let start = 0;
  letFrame = {isFinal: (data[start] &0x80) === 0x80, opcode: data[start++] &0xf, and marshals-masked: (data[start] & 0x80) === 0x80, payloadLen: data[start++] & 0x7F,// maskingKey:' ',
    payloadData: null
  };
// if 0-125, that is the  payload length
// If 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length
// If 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the most significant bit MUST be 0) are the payload length.
  if(frame.payloadLen === 126) {// If equal to 126, the next two bytes are the length //data[3] + data[4]; frame.payloadLen = (data[start++] << 8) + data[start++]; }else if(frame.payloadLen === 127) {// If equal to 127 the next 8 bytes are the length frame.payloadLen = 0;for (leti = 7; i >= 0; --i) { frame.payloadLen += (data[start++] << (i * 8)); }}if (frame.payloadLen) {
    if (frame.masked) {
      const maskingKey = [
        data[start++],
        data[start++],
        data[start++],
        data[start++]
      ];

      frame.maskingKey = maskingKey;
      // Octet i of the transformed data ("transformed-octet-i") is the XOR of octet i of the 
      //original data ("original-octet-i") with octet at indexi modulo 4 of the masking key ("masking-key-octet-j") : // j = i MOD 4 //transformed-octet-i = original-octet-i XOR masking-key-octet-j frame.payloadData = data .slice(start, Start + frame.payloadLen)// The length of intercepted data is in bytes. Map ((byte, IDx) => byte ^ maskingKey[IDx % 4]); / / decryption}else{ frame.payloadData = data.slice(start, start + frame.payloadLen); // No decryption required}}return frame;
}


functionEncodeWsFrame (data) {const isFinal = data.isfinal! == undefined ? data.isFinal :true, opcode = data.opcode ! == undefined ? data.opcode : 1, payloadData = data.payloadData ? Buffer.from(data.payloadData) : null, payloadLen = payloadData ? payloadData.length : 0;let frame = [];

  if (isFinal) frame.push((1 << 7) + opcode);
  else frame.push(opcode);

  if (payloadLen < 126) {
    frame.push(payloadLen);
  } else if (payloadLen < 65536) {// 127*2^8 + 127
    frame.push(126, payloadLen >> 8, payloadLen & 0xFF);
  } else {
    frame.push(127);
    for (let i = 7; i >= 0; --i) {
      frame.push((payloadLen & (0xFF << (i * 8))) >> (i * 8));
    }
  }

  frame = payloadData ? Buffer.concat([Buffer.from(frame), payloadData]) : Buffer.from(frame);
  return frame;
}
Copy the code

Html

<! DOCTYPE html> <html lang="en">
<head> 
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    p.me::after{
      content: 'M';
      margin-left:5px;
    }
    p.others::before{
      content: 'U';
      margin-right: 5px;
    }
    p.me{
      text-align: right;
    }
    p.me::after,p.others::before{
      display: inline-block;
      width:30px;
      height: 30px;
      color:coral;
      border:1px solid # 999;
      line-height: 30px;
      text-align: center;
      border-radius: 100px;
    }
    .messages{
      width: 500px;
      height: 800px;
      border: 1px solid #eee;
      padding: 10px;
    }
  </style>
</head>
<body>
  <input type="text" id="message-input" />
  <button id="submit"<div id="app" class="messages">
    
  </div>
  <script>
  function addMessage(className,data){
    const p = document.createElement('p')
    p.innerHTML = data;
    p.classList.add(className);
    document.querySelector('#app').appendChild(p); } / /let ws = new WebSocket("ws://localhost:8181");
  let ws = new WebSocket("ws://localhost:8083");
  let messageInput = document.querySelector('#message-input');
  document.querySelector('#submit').addEventListener('click',()=>{
    console.log(messageInput.value);
    addMessage('me',messageInput.value);
    ws.send(messageInput.value);
    messageInput.value = "";
  },false);
  ws.onopen= function(){
    console.log("start");
  }
  ws.onmessage = function(e){
    console.log("Client: message received to the server"+e.data);
    addMessage('others',e.data);
  }

  </script>
</body>
</html>

Copy the code