基于WebSocket实现实时聊天

前言

WebSocket是一种基于TCP协议的全双工通信协议,它通过一个初始的握手过程建立连接,然后保持连接开放,双方可以随时向对方发送消息。这与传统的HTTP通信不同,HTTP通信需要客户端发起请求,服务器响应后连接就会关闭,而WebSocket则支持双向通信,允许服务器主动向客户端推送数据。

实时聊天对话中的WebSocket应用

在实时聊天对话中,实时性对于提供出色的用户体验至关重要。WebSocket的引入使得开发者能够轻松实现实时消息传递,而不必依赖传统的轮询方式。

WebSocket的优势

  1. 低延迟通信: WebSocket通过建立持久连接,降低了通信的延迟。消息可以即时传递,使得用户能够实时看到对方的消息。
  2. 双向通信: 与HTTP不同,WebSocket支持双向通信,服务器可以主动推送消息给客户端,而不需要等待客户端的请求。
  3. 减轻服务器压力: 相比传统的轮询方式,WebSocket减轻了服务器的负担。在WebSocket中,连接保持开放,减少了频繁的连接和断开操作。
/**
 * 发起websocket请求函数
 * @param {object} wsObj  - ws对象
 *  @param {string} type  - 操作websocket:销毁close、创建create
 *  @param {number} timeout  - 心跳间隔时长,默认5000ms
 * @param sendHeartBeat  - 以心跳,内容体区分string、object
 * @param {function} msgCallback  - 接收到ws数据,对数据进行处理的回调函数
 * @param {function} reCallback  - ws每次重连时,暴露对外的回调函数
 */



export function websocketCommand(wsObj,type,timeout=5000, sendHeartBeat, msgCallback, reCallback, openCallback) {
  let lockReconnect = false;  // 是否真正建立连接
  let timeoutnum = null;  // 断开 重连倒计时


  //心跳检测
  let heartCheck = {
    timeout: 55000, //1分钟发一次心跳,时间设置小一点较好(50-60秒之间)
    timeoutObj: null,
    serverTimeoutObj: null,
    reset: function () {
      clearTimeout(this.timeoutObj);
      clearTimeout(this.serverTimeoutObj);
      return this;
    },
    start: function () {
      let self = this;
      this.timeoutObj = setTimeout(function () {
        //这里发送一个心跳,后端收到后,返回一个心跳消息,
        //onmessage拿到返回的心跳就说明连接正常
        if(wsObj.readyState === 1) {
          websocketSend()
        }
        self.serverTimeoutObj = setTimeout(function () {//如果超过一定时间还没重置,说明后端主动断开了
          wsObj.close(); //如果onclose会执行reconnect,我们执行socket.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
        }, self.timeout)
      }, this.timeout)
    }
  }

  // 若type传入close,则意图销毁websocket
  if(type==='close'){
    onClose('close');
  }
  // 若type传入create,则意图新建websocket,需初始化ws并发送心跳
  if(type==='create'){
    initWebsocket();
    websocketSend();
  }

  function initWebsocket(){
    if (typeof (WebSocket) === 'undefined') {
      console.log('您的浏览器不支持WebSocket,无法获取数据');
      return false;
    }
    wsObj.onmessage = function (e) { onMessage(e) };
    wsObj.onopen = function (e) { onOpen(e) };
    wsObj.onerror = function (e) { onError(e) };
    wsObj.onclose = function (e) { onClose(e) } ;
  }

  function websocketSend () {
    // 加延迟是为了尽量让ws连接状态变为OPEN
    setTimeout(() => {
      wsObj.send(sendHeartBeat)
    }, 500)
  }

  function onMessage(evt) {
    var received_msg = evt && JSON.parse(evt.data);
    msgCallback(received_msg);

    // 收到服务器信息, 重置服务器心跳
    heartCheck.reset().start(); //心跳检测重置
  }

  function onError(e) {
    reconnect();  //尝试重新连接
    console.log('连接错误', e);
  }

  function onOpen(e) {
    console.log('连接开启', e)
    // 连接成功向服务器发送信息,并开启心跳
    if(openCallback){
      openCallback()
    }
    heartCheck.reset().start(); //心跳检测重置
  }
  function reconnect(e) {
    console.log('执行重连', e)
    // 避免重复建立连接
    if (lockReconnect) {
      return;
    }
    lockReconnect = true;
    // 没连接上会一直重连,设置延迟避免请求过多
    timeoutnum && clearTimeout(timeoutnum);
    timeoutnum = setTimeout(function() {
      // 重连
      initWebsocket();
      // 若重连后有需额外处理的逻辑,通过reCallback()回调暴露出去
      // reCallback?.();
      lockReconnect = false;
    }, timeout);
  }

  function onClose(e) {
    if(typeof e === 'string') {
      console.log('断开链接');
      // 如果ws连接正常,则清计时器、断开连接
      wsObj?.close?.();
      heartCheck.reset()
    } else {
      reconnect();  //尝试重新连接
      console.log('连接关闭', e);
    }
  }
}


结语:在使用过程当中我们还需要注意网络断开链接的情况,以及组件销毁的情况,我们要及时销毁,避免不必要的资源占用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值