博客
关于我
node系列:初探websocket
阅读量:277 次
发布时间:2019-03-01

本文共 5101 字,大约阅读时间需要 17 分钟。

简介

很多网站的实时推送技术,所用的技术大多都是 Ajax 轮询。也就是隔几秒请求一次接口,显然这样会浪费很多的带宽等资源。WebSocket 允许服务端主动向客户端推送数据,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

特点

  • 双向通信
  • 没有同源策略(客户端可以与任意服务器通信)
  • 二进制支持

工具

客户端实现

function WebSocketTest () {     if ("WebSocket" in window) {       console.log("您的浏览器支持 WebSocket!");    // 打开一个 web socket    var ws = new WebSocket("ws://localhost:9998/echo");    ws.onopen = function () {         // Web Socket 已连接上,使用 send() 方法发送数据      ws.send("发送数据");      alert("数据发送中...");    };    ws.onmessage = function (evt) {         var received_msg = evt.data;      alert("数据已接收...");    };    ws.onclose = function () {         // 关闭 websocket      alert("连接已关闭...");    };  }  else {       // 浏览器不支持 WebSocket    alert("您的浏览器不支持 WebSocket!");  }}

后台实现(node)

由于原生的node实现起来非常复杂,需要牵扯到一些底层的如数据帧的编码解码,所以我们这里直接用已经实现好的第三方库,比如socket.io,WebSocket-Node

var app = require('express')();var http = require('http').Server(app);var io = require('socket.io')(http);app.get('/', function (req, res) {     res.send('

Welcome Realtime Server

');});io.on('connection', function (socket) { console.log('a user connected'); socket.on("disconnect", function () { console.log("a user go out"); }); socket.on("message", function (obj) { io.emit("message", obj); });});http.listen(3000, function () { console.log('listening on *:3000');});
  
Document

    简易的控制台版的聊天室

    客户端心跳机制的实现

    WebSocket并不稳定,在使用一段时间后,可能会断开连接,貌似至今没有一个为何会断开连接的公论,所以我们需要让WebSocket保持连接状态,这里推荐两种方法。

    1、class类中就是用的这种方式:设置一个变量,在webSocket关闭/报错的回调中,判断是不是手动关闭的,如果不是的话,就重新连接,这样做的优缺点如下:

    • 优点:请求较少(相对于心跳连接),易设置。
    • 缺点:可能会导致丢失数据,在断开重连的这段时间中,恰好双方正在通信。

    2、客户端就像心跳一样每隔固定的时间发送一次ping,来告诉服务器,我还活着,而服务器也会返回pong,来告诉客户端,服务器还活着。具体方法再下文注释中。

    class WebSocketClass {       /**     * @description: 初始化实例属性,保存参数     * @param {String} url ws的接口     * @param {Function} msgCallback 服务器信息的回调传数据给函数     * @param {String} name 可选值 用于区分ws,用于debugger     */    constructor(url, msgCallback, name = 'default') {           this.url = url;        this.msgCallback = msgCallback;        this.name = name;        this.ws = null;  // websocket对象        this.status = null; // websocket是否关闭    }    /**     * @description: 初始化 连接websocket或重连webSocket时调用     * @param {*} 可选值 要传的数据     */    connect(data) {           // 新建 WebSocket 实例        this.ws = new WebSocket(this.url);        this.ws.onopen = e => {               // 连接ws成功回调            this.status = 'open';            console.log(`${     this.name}连接成功`, e)            // this.heartCheck();            if (data !== undefined) {                   // 有要传的数据,就发给后端                return this.ws.send(data);            }        }        // 监听服务器端返回的信息        this.ws.onmessage = e => {               // 把数据传给回调函数,并执行回调            // if (e.data === 'pong') {               //     this.pingPong = 'pong'; // 服务器端返回pong,修改pingPong的状态            // }            return this.msgCallback(e.data);        }        // ws关闭回调        this.ws.onclose = e => {               this.closeHandle(e); // 判断是否关闭        }        // ws出错回调        this.onerror = e => {               this.closeHandle(e); // 判断是否关闭        }    }    // heartCheck() {       //     // 心跳机制的时间可以自己与后端约定    //     this.pingPong = 'ping'; // ws的心跳机制状态值    //     this.pingInterval = setInterval(() => {       //         if (this.ws.readyState === 1) {       //             // 检查ws为链接状态 才可发送    //             this.ws.send('ping'); // 客户端发送ping    //         }    //     }, 10000)    //     this.pongInterval = setInterval(() => {       //         this.pingPong = false;    //         if (this.pingPong === 'ping') {       //             this.closeHandle('pingPong没有改变为pong'); // 没有返回pong 重启webSocket    //         }    //         // 重置为ping 若下一次 ping 发送失败 或者pong返回失败(pingPong不会改成pong),将重启    //         console.log('返回pong')    //         this.pingPong = 'ping'    //     }, 20000)    // }    // 发送信息给服务器    sendHandle(data) {           console.log(`${     this.name}发送消息给服务器:`, data)        return this.ws.send(data);    }    closeHandle(e = 'err') {           // 因为webSocket并不稳定,规定只能手动关闭(调closeMyself方法),否则就重连        if (this.status !== 'close') {               console.log(`${     this.name}断开,重连websocket`, e)            // if (this.pingInterval !== undefined && this.pongInterval !== undefined) {               //     // 清除定时器            //     clearInterval(this.pingInterval);            //     clearInterval(this.pongInterval);            // }            this.connect(); // 重连        } else {               console.log(`${     this.name}websocket手动关闭`)        }    }    // 手动关闭WebSocket    closeMyself() {           console.log(`关闭${     this.name}`)        this.status = 'close';        return this.ws.close();    }}function someFn(data) {       console.log('接收服务器消息的回调:', data);}// const wsValue = new WebSocketClass('ws://121.40.165.18:8800', someFn, 'wsName'); // 这个链接一天只能发送消息50次const wsValue = new WebSocketClass('wss://echo.websocket.org', someFn, 'wsName'); // 阮一峰老师教程链接wsValue.connect('立即与服务器通信'); // 连接服务器// setTimeout(() => {   //     wsValue.sendHandle('传消息给服务器')// }, 1000);// setTimeout(() => {   //     wsValue.closeMyself(); // 关闭ws// }, 10000)

    转载地址:http://dipo.baihongyu.com/

    你可能感兴趣的文章
    mysql case when 乱码_Mysql CASE WHEN 用法
    查看>>
    Multicast1
    查看>>
    mysql client library_MySQL数据库之zabbix3.x安装出现“configure: error: Not found mysqlclient library”的解决办法...
    查看>>
    MySQL Cluster 7.0.36 发布
    查看>>
    Multimodal Unsupervised Image-to-Image Translation多通道无监督图像翻译
    查看>>
    MySQL Cluster与MGR集群实战
    查看>>
    multipart/form-data与application/octet-stream的区别、application/x-www-form-urlencoded
    查看>>
    mysql cmake 报错,MySQL云服务器应用及cmake报错解决办法
    查看>>
    Multiple websites on single instance of IIS
    查看>>
    mysql CONCAT()函数拼接有NULL
    查看>>
    multiprocessing.Manager 嵌套共享对象不适用于队列
    查看>>
    multiprocessing.pool.map 和带有两个参数的函数
    查看>>
    MYSQL CONCAT函数
    查看>>
    multiprocessing.Pool:map_async 和 imap 有什么区别?
    查看>>
    MySQL Connector/Net 句柄泄露
    查看>>
    multiprocessor(中)
    查看>>
    mysql CPU使用率过高的一次处理经历
    查看>>
    Multisim中555定时器使用技巧
    查看>>
    MySQL CRUD 数据表基础操作实战
    查看>>
    multisim变压器反馈式_穿过隔离栅供电:认识隔离式直流/ 直流偏置电源
    查看>>