websocket1

扫码查看

WebSocket

首先介绍下什么是WebSocket

为什么要使用WebSocket(WebSocket与传统HTTP有什么优势)

  • 客户端与服务端只建立一个TCP连接,可以使用更少的连接
  • 服务器可以推送数据到客户端,比HTTP请求响应模式更灵活,更高效
  • 更轻量级的协议头,减少数据传送量

WebSocket 握手

客户端建立连接时,通过HTTP发起请求报文

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

与HTTP请求协议有区别的部分:

Upgrade: websocket
Connection: Upgrade

Sec-WebSocket-Key 用安全校验:

Sec-WebSocket-Protocol: chat, superchat

Sec-WebSocket-Version: 13

服务端处理完请求后,响应报文如下:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade

Sec-WebSocket-Accep:

Sec-WebSocket-Protocol:

客户端代码

let ws = new WebSocket('ws://192.168.10.40:3000/')
      ws.onopen = mes=>{
        console.log(mes,'aaa')
  }

服务端代码

const net = require('net');
const crypto = require('crypto');
const wsGUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
net.createServer(function(socket) {
    socket.on('data', function(buffer) {
        // data 是buffer需要转化
        const data = buffer.toString(),
            key = getWebSocketKey(data),
            acceptKey = crypto.createHash('sha1').update(key + wsGUID).digest('base64'),
            headers = [
                'HTTP/1.1 101 Switching Protocols',
                'Upgrade: websocket',
                'Connection: Upgrade',
                'Sec-WebSocket-Accept: ' + acceptKey
                ];
        socket.write(headers.concat('','').join('\r\n'));
    })
}).listen(3000)

function getWebSocketKey(dataStr) {
    var match = dataStr.match(/Sec\-WebSocket\-Key:\s(.+)\r\n/);
    if (match) {
        return match[1];
    }
}

客户端的API

1.websocket 构造函数

var ws = new WebSocket('ws://localhost:8080');

执行上面语句之后,客户端就会与服务器进行连接。下面这张图是实例对象的所有属性和方法清单

2.webSocket.readyState

console.log(ws.readyState) // 我们可以输入看当前是什么状态
  • CONNECTING:值为0,表示正在连接。
  • OPEN:值为1,表示连接成功,可以通信了。
  • CLOSING:值为2,表示连接正在关闭。
  • CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

3.webSocket.onopen

ws.onopen = function () {
  ws.send('Hello Server!');
}
ws.addEventListener('open', function (event) {
  ws.send('Hello Server!');
});

4.webSocket.onclose

ws.onclose = function(event) {
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;
  // handle close event
};

5.webSocket.onmessage

ws.onmessage = function(event) {
  var data = event.data;
  // 处理数据
};

ws.addEventListener("message", function(event) {
  var data = event.data;
  // 处理数据
});

6.webSocket.send()

ws.send('your message');

7.webSocket.bufferedAmount

var data = new ArrayBuffer(10000000);
socket.send(data);

if (socket.bufferedAmount === 0) {
  // 发送完毕
} else {
  // 发送还没结束
}

8.webSocket.onerror

socket.onerror = function(event) {
  // handle error event
};

socket.addEventListener("error", function(event) {
  // handle error event
});

完整示例

服务端

import userInfoModel from '../model/userinfo';
import addendanceInfoModel from '../model/addentance';
import Websocket from 'ws';
import * as http from 'http';
const wss = new Websocket.Server({port: 3004});
wss.on('connection',function(ws:Websocket,req:http.IncomingMessage) {
    ws.on('message',async function(){
        try{
            // 获取基本数据
            const userData = await userInfoModel.find();
            ws.send(JSON.stringify(userData));
            // 获取出勤数据
            const addendanceData = await addendanceInfoModel.find();
            ws.send(JSON.stringify(addendanceData))
        }catch(err){
            ws.close()
        }
    })
})

前端websocket

// Ws 封装一系列websock方法
// getInstance   获取当前类的实例
// initConnect   初始化连接,返回promise,连接成功resolve,失败reject
// send   发送数据,包括断开重新连接
export default class Ws{
    constructor(){
        // 初始化连接
        this.initConnect()
    }
    static getInstance() {
        if(!this.instance){
            this.instance = new Ws()
        }
        return this.instance;
    }
    initConnect(){
        // 创建ws实例
        return new Promise((resolve,reject)=>{
            this.ws = new WebSocket('ws://192.168.10.40:3004/');
            this.ws.onmessage = event => this.message(JSON.parse(event.data));
            this.ws.onopen = event => resolve(event);
            this.ws.onclose = event => reject(event);
        })
    }
    async send(data){
        // 如果为连接断开就重新连接
        if(this.ws.readyState == 3 ){
            // 初始化连接
            await this.initConnect();
            // 连接成功发送消息
            data && this.ws.send(JSON.stringify(data))
        }else{
            // 发送消息
            data && this.ws.send(JSON.stringify(data))
        }
    }
    close() {
        if(this.ws.readyState == 3){
            return;
        }
        this.ws.close();
    }
}

前端组件部分

<script>
import Ws from '@/assets/websocket.js';
export default {
  name: 'HelloWorld',
  mounted() {
    this.ws = Ws.getInstance();
    this.ws.message = this.onmessage;
  },
  methods:{
    onmessage(data) {
      console.log(data,'数据')
    },
    OnClick() {
      this.ws.send({})
    }
  }
}
</script>

websocket 遇到的坑

  proxy_read_timeout 60s;
  proxy_send_timeout 60s;

proxy_read_timeout 60s:

proxy_send_timeout 60s;

我们只需找运维同学帮我们把代理时间延长,就不会出现超时时间了

我们在代码中也可以设置断开重连

    initConnect(){
        // 创建ws实例
        return new Promise((resolve,reject)=>{
            this.ws = new WebSocket('ws://192.168.10.40:3004/');
            this.ws.onmessage = event => this.message(JSON.parse(event.data));
            this.ws.onopen = event => resolve(event);
            this.ws.onclose = event => reject(event);
        })
    }
    async send(data){
        // 如果为连接断开就重新连接
        if(this.ws.readyState == 3 ){
            // 初始化连接
            await this.initConnect();
            // 连接成功发送消息
            data && this.ws.send(JSON.stringify(data))
        }else{
            // 发送消息
            data && this.ws.send(JSON.stringify(data))
        }
    }
01-11 07:03
查看更多