• NodeJs 实现 WebSocket 即时通讯(版本二)


    服务端代码

    websocket.js

    'use strict'
    
    const WebSocket = require('ws');
    const connections = new Map();
    const Constr = function(port) {
      const self = this;
      self.webSocket = new WebSocket.Server({ port: port });
    };
    Constr.prototype.connect = function() {
      const self = this;
      self.webSocket.on('connection', function connection(ws) {
        try {
          ws.on('message', function incoming(message) {
            try {
              if (connections.size > 2000) { 
                ws.send(1);
                ws.close();
                return;
              }
              ws.send(0);
              if (connections.get(message) && connections.get(message).ws.readyState == WebSocket.OPEN) {
                connections.get(message).date = Date.now();
                connections.get(message).ws.isAlive = true;
                console.log(message + ':上次心跳时间' + connections.get(message).date);
                return;
              }
              connections.set(message, {
                ws: ws,
                date: Date.now(),
              });
              console.log('客户端imei:' + message + '握手、心跳成功!时间:' + connections.get(message).date);
              ws.on('close', function close() {
    
                console.log('连接关闭   ' +  message)
                // ws.reconnect();
                if (connections.get(message)) {
                  connections.delete(message);
                }
                ws.close();
              });
              ws.on('error', function close() {
                console.error(message + ':出现错误!强制下线');
                connections.get(message)
                  .ws
                  .close();
              });
              // 服务器接受pong消息++huanglong,确定mtk接受ping,并pong服务器后打开
              // ws.on('pong', function() {
              //   connections.get(message).date = Date.now();
              //   connections.get(message).ws.isAlive = true;
              //   console.log('上次接收pong时间' + connections.get(message).date);
              // });
            } catch (e) {
              console.error('on message error:', e);
            }
          });
        }catch (e) {
          console.error('on connection error:', e);
        }
      });
      self.webSocket.on('error',function(){
        console.log('error');
      });
    };
    Constr.prototype.send = function(obj) {
      console.log('下推消息:' + JSON.stringify(obj));
      const imeiArray = obj.imei.split(',');
      for (let i = 0; i < imeiArray.length; i++) {
        try {
          if (connections.get(imeiArray[i]) && connections.get(imeiArray[i]).ws.readyState === WebSocket.OPEN) {
            console.log(imeiArray[i] + ':连接状态' + connections.get(imeiArray[i]).ws.readyState);
            connections.get(imeiArray[i]).ws.send(obj.str);
          } else {
            console.log('imei:' + imeiArray[i] + 'socket关闭!');
            connections.delete(imeiArray[i]);
          }
        } catch (e) {
          console.log('发送消息发生严重错误!imei:' + imeiArray[i]);
        }
      }
    };
    
    
    Constr.prototype.heartbeatCheck = function() {
      console.log('心跳检查:当前握手连接数为' + connections.size + '客户端:' + connections.keys().toString());
      if (connections.size === 0) {
        return;
      }
      connections.forEach(function (value, key) {
        if (Date.now() - value.date > 60000) {
          connections.delete(key);
          try {
            value.ws.close();
          }catch (e) {
            console.error('close error', e);
          }
        }
        // ++huanglong,暂时关闭ping机制,确定mtk接受ping,并pong服务器后打开
        // if (value.ws.isAlive === false) return value.ws.terminate();
        // value.ws.isAlive = false;
        // value.ws.ping(function() {
        //   value.ws.send(2);
        // });
      });
    };
    // Constr.prototype.testyuyin2 = function() {
    //   connections.forEach(function(value) {
    //     value.ws.send('测试语音');
    //   });
    // };
    module.exports = Constr;

    app.js

    const Ws = require('./app/middleware/websocket');
    
    const ws = new Ws(8080);
    try {
        ws.connect();
    } catch (e) {
        console.error('ws connect error:', e);
    }
    
    console.log("WebSocket建立完毕")

    客户端

    const WebSocket = require('ws');
    
    var lockReconnect = false;//避免重复连接
    var wsUrl = "ws://127.0.0.1:8080";
    var ws;
    var tt;
    function createWebSocket() {
        try {
            ws = new WebSocket(wsUrl);
            init();
        } catch (e) {
            console.log('catch' + e);
            reconnect(wsUrl);
        }
    }
    function init() {
        ws.onclose = function () {
            console.log('链接关闭');
            reconnect(wsUrl);
        };
        ws.onerror = function () {
            console.log('发生异常了');
            reconnect(wsUrl);
        };
        ws.onopen = function () {
            //心跳检测重置
            heartCheck.start();
        };
        ws.onmessage = function (event) {
            //拿到任何消息都说明当前连接是正常的
            console.log('接收到消息' + JSON.stringify(event.data));
            heartCheck.start();
        }
    }
    function reconnect(url) {
        if (lockReconnect) {
            return;
        };
        lockReconnect = true;
        //没连接上会一直重连,设置延迟避免请求过多
        tt && clearTimeout(tt);
        tt = setTimeout(function () {
            createWebSocket(url);
            lockReconnect = false;
        }, 4000);
    }
    //心跳检测
    var heartCheck = {
        timeout: 3000,
        timeoutObj: null,
        serverTimeoutObj: null,
        start: function () {
            // console.log('start');
            var self = this;
            this.timeoutObj && clearTimeout(this.timeoutObj);
            this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
            this.timeoutObj = setTimeout(function () {
                //这里发送一个心跳,后端收到后,返回一个心跳消息,
                ws.send("666666");
                self.serverTimeoutObj = setTimeout(function () {
                    // console.log(111);
                    // console.log(ws);
                    ws.close();
                    // createWebSocket();
                }, self.timeout);
    
            }, this.timeout)
        }
    }
    createWebSocket(wsUrl);
  • 相关阅读:
    疯狂学java的第七天
    疯狂学java的第六天
    疯狂学java的第五天
    学java的第四天
    学java的第三天
    javaSE_20_常用API(包装类丶BigInteger类丶BigDecimal类 )
    javaSE_19_常用API(String类丶StringBuffer类)
    javaSE_17_内部类丶常用的引用类型用法总结
    javaSE_15_package和import丶访问控制权限
    javaSE_14_抽象类丶接口
  • 原文地址:https://www.cnblogs.com/zyulike/p/11434032.html
Copyright © 2020-2023  润新知