WebSocket原理

109 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

什么是socket?

socket倒不是什么协议,在网络中其实是一个抽象层。任何一个计算机语言要进行网络通信的话基本上都是通过socket抽象层进行通信。它是基于TCP/IP协议的。

  1. 客户端链接服务器,三次握手建立连接通道。
  2. 客户端和服务端通过socket接口发送和接收消息。任何一端在任何时候都可以向另一端发送任何消息。
  3. 有一端断开,通道销毁。

HTTP

HTTP是建立在socket之上的。

  1. 客户端连接服务器,三次握手,建立连接通道。
  2. 客户端发送一个http格式消息(消息头、消息体),服务器响应http格式消息。
  3. 客户端或服务器断开,通道销毁。

http的问题在于,如果我们对某一要求实时性要求非常高,每一次交互都是客户端发起的,而消息的变动在服务器但是无法主动发送给客户端。
遇到这种问题,一般有以下解决方法:

  1. 轮询: 会造成很多无用的请求,增加内存开销。
  2. 长连接(keep-alive):服务器不会主动断开,如果服务器不给响应,浏览器就会一直等待,等消息变了才发送。

websocket

在HTML5出现之后,推出浏览器支持的websocket协议也推出基于websocket的web API。
websocket专门用来解决时事消息的事情。

  1. 客户端连接服务器,三次握手,建立连接通道。
  2. 客户端发送一个http格式的消息(特殊格式),服务器也响应一个http格式的消息(特殊格式),称为http握手。(确认是否支持socket)
  3. 双方自由通信,通信格式按照websocket的要求进行
  4. 客户端或服务器断开,通道销毁。
    // 客户端 创建websocket 
    // 发送连接到服务器
    const ws = new WebSocket("ws://localhost:8080");
    //当连接建立运行的事件
    ws.onopen = function() {
        console.log('连接建立');
    }
    
    // 接收数据的事件
    ws.onmessage = function(e){
        console.log('来自服务器的数据', e.data);
    }
    
    // 发送数据到服务器
    ws.send('123');
    
    // 客户端主动断开
    ws.close();
    
    // 任何一方断开连接运行的事件
    ws.onclose = function() {
        console.log('通道关闭')
    }
// 服务端 用net模块创建服务
    const net = require('net');
    const server = net.createServer((socket)=>{
        console.log('收到客户端的连接');
        // 向浏览器发送确认信息
        socket.once('data', chunk => {
            const httpContent = chunk.toString('utf-8');
            let parts = httpContent.split('\r\n');
            parts.shift();
            parts = parts.filter(s=>s).map(s=>{
                const i = s.indexof(":");
                return [s.substr(0,i), s.substr(i+1).trim()];
            })
            const headers = Object.formEntries(parts);
            const crypto = require('crypto');
            const hash = crypto.createHash('sha1');
            hash.update(
                headers['Sec-WebSocket-Key'] + "258EAFA5-E914-47DA-95CA-C5AB0DC85V11"
            );
            cibst key = hash.digest('base64');
            socket.write(`HTTP/1.1 101  Switching Protocols
Upgrade:websocket
Connection:Upgrade
sec-WebSocket-Accept:${key}
`);
        })
    });
    server.listen(8080)