node 原生实现websocket

 server.js

const http = require('http');
const crypto = require('crypto');

const server = http.createServer(function (req,res) {
    res.writeHead(200,{'Content-type':'text/plain'});
    res.end('hello world');
});

server.listen(80);

server.on('upgrade',function (req,socket,upgradeHead) {
    const head = new Buffer(upgradeHead.length);

    upgradeHead.copy(head);
    let key = req.headers['sec-websocket-key'];
    let shasum = crypto.createHash('sha1');
    const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; //协议中规定的校验用GUID,这是算法中要用到的固定字符串
    key = shasum.update(`${key}${GUID}`).digest('base64');

    let headers = [
        'HTTP/1.1 101 Web Socket Protocol Handshake',
        'Upgrade: websocket',
        'Connection: Upgrade',
        'Sec-Websocket-Accept: '+key,
    ];
    socket.setNoDelay(true);
    socket.write(headers.concat('','').join('\r\n'));

    socket.on('data',(e)=>{
        //接收数据
        console.log(decodeDataFrame(e));

    });



})

//数据帧的解码
function decodeDataFrame(e){
    var i=0,j,s,frame={
        //解析前两个字节的基本数据
        FIN:e[i]>>7,Opcode:e[i++]&15,Mask:e[i]>>7,
        PayloadLength:e[i++]&0x7F
    };
    //处理特殊长度126和127
    if(frame.PayloadLength==126)
        frame.length=(e[i++]<<8)+e[i++];
    if(frame.PayloadLength==127)
        i+=4, //长度一般用四字节的整型,前四个字节通常为长整形留空的
            frame.length=(e[i++]<<24)+(e[i++]<<16)+(e[i++]<<8)+e[i++];
    //判断是否使用掩码
    if(frame.Mask){
        //获取掩码实体
        frame.MaskingKey=[e[i++],e[i++],e[i++],e[i++]];
        //对数据和掩码做异或运算
        for(j=0,s=[];j<frame.PayloadLength;j++)
            s.push(e[i+j]^frame.MaskingKey[j%4]);
    }else s=e.slice(i,frame.PayloadLength); //否则直接使用数据
    //数组转换成缓冲区来使用
    s=new Buffer(s);
    //如果有必要则把缓冲区转换成字符串来使用
    if(frame.Opcode==1)s=s.toString();
    //设置上数据部分
    frame.PayloadData=s;
    //返回数据帧
    return frame;
}
//数据帧的编码
function encodeDataFrame(e){
    var s=[],o=new Buffer(e.PayloadData),l=o.length;
    //输入第一个字节
    s.push((e.FIN<<7)+e.Opcode);
    //输入第二个字节,判断它的长度并放入相应的后续长度消息
    //永远不使用掩码
    if(l<126) s.push(l);
    else if(l<0x10000) s.push(126,(l&0xFF00)>>2,l&0xFF);
    else s.push(
            127, 0,0,0,0, //8字节数据,前4字节一般没用留空
            (l&0xFF000000)>>6,(l&0xFF0000)>>4,(l&0xFF00)>>2,l&0xFF
        );
    //返回头部分和数据部分的合并缓冲区
    return Buffer.concat([new Buffer(s),o]);
}

html

<!DOCTYPE HTML>
<html>
   <head>
   <meta charset="utf-8">
   <title></title>
    
      <script type="text/javascript">

               // 打开一个 web socket
               var ws = new WebSocket("ws://localhost");
                
               ws.onopen = function()
               {
                  // Web Socket 已连接上,使用 send() 方法发送数据
                  ws.send('胜多负少');
                  console.log("数据发送中...");
               };
                
               ws.onmessage = function (evt) 
               { 
                  var received_msg = evt.data;
                  console.log("数据已接收...");
               };
                
               ws.onclose = function()
               { 
                  // 关闭 websocket
                  console.log("连接已关闭..."); 
               };
            
            
   
      </script>
        
   </head>
   <body>
   
     
      
   </body>
</html>

参考 https://segmentfault.com/a/1190000000428502

     https://blog.csdn.net/chencl1986/article/details/88411056

猜你喜欢

转载自blog.csdn.net/qq_35014708/article/details/89249853