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);

 

posted @ 2019-08-30 11:24  橘子味儿的猫  阅读(709)  评论(1编辑  收藏  举报