浅谈websocket

一、什么是websocket?

  • 因为http 通信只能由客户端发起,服务器返回查询结果,HTTP 协议做不到服务器主动向客户端推送信息,服务器有连续的状态变化,客户端要获知就非常麻烦。

  • 我们只能使用轮询:每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。

  • 轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开);

  • WebSocket 是一种支持双向通讯网络通信协议。就是服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,属于服务器推送技术的一种.

二、websocket的特点

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据blob对象或Arraybuffer对象)

(5)收到的数据类型 可以使用binaryType 指定, 显式指定收到的二进制数据类型

(6)没有同源限制,客户端可以与任意服务器通信。

(7)协议标识符是ws(握手http)(如果加密,则为wss(tcp +TLS)),服务器网址就是 URL。

三、使用示例代码

let webSocket = null;
let lockReconnect = false;
let userId = Math.random()*1000;
let toUserId = Math.random()*1000;
const pageInfo = {
  'userId': userId, 'toUserId': toUserId, // 可多个用户同时连接
  pageActive: 0,
  video: 'pause',   // play/pause
  tabsInfo: {
    page0: 0,
    page1: 0,
  }
}

webSocketInit();

//心跳检测
let heartCheck = {
  timeout: 5000,
  timeoutObj: null,
  serverTimeOutObj: null,
  start: function () {
    console.log('start');
    this.timeoutObj && clearTimeout(this.timeoutObj);
    this.timeoutObj = setTimeout(function () {
      console.log('start心跳');
      if (webSocket.readyState == 1) {
        webSocket.send(JSON.stringify(pageInfo))
      }
      // 再设置个定时器,如果一直没连接上,就关闭websocket。webSocket.close();
      self.serverTimeOutObj = setTimeout(() =>
        {
          ws.onclose();
        }, this.timeout)
    }, this.timeout)
  }
}

function webSocketInit () {
  try {
    if ('WebSocket' in window) {
      webSocket = null
      webSocket = new WebSocket(
        // 此处填写你要连接的ws地址
        // TODO 互联网版本地址
        'wss://txw.lshr.cn:8011/websocket/' + userId
      )
    } else {
      alert('该浏览器不支持websocket!');
    }
  } catch (e) {
    websocketReconnect();  //尝试重连websocket
  }

  webSocket.onopen = function () {
    /* * 连接成功 * */
    console.log('通讯开始')
    heartCheck.start();
  }

  webSocket.onmessage = function () {
    // 收到消息时回调函数
    heartCheck.start();
  }

  webSocket.onclose = function (event) {
    console.log('连接关闭', event)
    lockReconnect = false;
    websocketReconnect();  //尝试重连websocket
  }


  webSocket.onerror = function (err) {
    console.log('err: ', err);
    lockReconnect = false;
    websocketReconnect();  //尝试重连websocket
  }
  window.onbeforeunload = function () {
    webSocket.close();
  }
}

/**
 * 重连ws
 */
function websocketReconnect () {
  if (lockReconnect) {       // 是否已经执行重连
    return;
  }
  lockReconnect = true;
  //没连接上会一直重连,设置延迟避免请求过多
  tt && clearTimeout(tt);
  var tt = setTimeout(function () {
    webSocketInit();
    lockReconnect = false;
    console.log('正在重连');
  }, 3000)
}

四、为什么需要WebSocket心跳检测

在实际应用中,可能会面临多种网络状况,例如:

1、客户端网络故障,可能会导致客户端无法发送和接收数据;

2、服务器网络故障,可能会导致客户端无法连接服务器;

3、防火墙或者代理等网络设备可能会拦截WebSocket通信,从而导致连接中断。

4、20分钟不给客户端send消息,连接就会自动断开连接。

为了应对这些可能的网络问题,我们需要使用WebSocket心跳检测机制来检测客户端的在线状态,避免无法处理掉线等异常情况。

心跳检测,重连概述

心跳检测:websocket连接成功之后,给服务器send一个消息,服务器会相应返回消息;收到消息之后又给给服务器send一个消息,如此往复,一直保持心跳。(注意:实际在开发中,我并没有在收到消息时又send消息,只是在websocket关闭之后,重连)

重连:websocket关闭之后,需要重新连接。

WebSocket心跳检测的注意事项

在使用WebSocket心跳检测时,我们需要注意以下几个问题:

1、心跳包的发送间隔应该根据具体情况进行调整,一般建议不要过长,例如30秒或者1分钟。

2、心跳包的消息内容应该尽量精简,避免浪费带宽;

3、心跳间隔和最长超时时间的设置需要考虑网络状况和服务器负载等因素;

4、在检测到客户端掉线时,需要及时关闭WebSocket连接,并且从客户端信息列表中删除该客户端。

其它注意事项:

https协议 对应 wws

http协议对应ws

// 开发过程因为没有在状态码1001情况下send消息,导致报错(状态码1002)
// send需要在websocket正常连接时才可以

// 发送JSON.stringify数据(如果不发送JSON.stringify类型的数据的话,需要服务端设置下)

if (webSocket.readyState == 1) {
   webSocket.send(JSON.stringify(pageInfo))
}

五、 websocket在线测试 

六、状态码

状态码名称描述
0–999-保留段, 未使用。
1000CLOSE_NORMAL正常关闭; 无论为何目的而创建, 该链接都已成功完成任务。
1001CLOSE_GOING_AWAY终端离开, 可能因为服务端错误, 也可能因为浏览器正从打开连接的页面跳转离开。
1002CLOSE_PROTOCOL_ERROR由于协议错误而中断连接。
1003CLOSE_UNSUPPORTED由于接收到不允许的数据类型而断开连接 (如仅接收文本数据的终端接收到了二进制数据)。
1004-保留。 其意义可能会在未来定义。
1005CLOSE_NO_STATUS保留。 表示没有收到预期的状态码。
1006CLOSE_ABNORMAL保留。 用于期望收到状态码时连接非正常关闭 (也就是说, 没有发送关闭帧)。
1007Unsupported Data由于收到了格式不符的数据而断开连接 (如文本消息中包含了非 UTF-8 数据)。
1008Policy Violation由于收到不符合约定的数据而断开连接。 这是一个通用状态码, 用于不适合使用 1003 和 1009 状态码的场景。
1009CLOSE_TOO_LARGE由于收到过大的数据帧而断开连接。
1010Missing Extension客户端期望服务器商定一个或多个拓展, 但服务器没有处理, 因此客户端断开连接。
1011Internal Error客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接。
1012Service Restart服务器由于重启而断开连接。 [Ref]
1013Try Again Later服务器由于临时原因断开连接, 如服务器过载因此断开一部分客户端连接。 [Ref]
1014-由 WebSocket 标准保留以便未来使用。
1015TLS Handshake保留。 表示连接由于无法完成 TLS 握手而关闭 (例如无法验证服务器证书)。
1016–1999-由 WebSocket 标准保留以便未来使用。
2000–2999-由 WebSocket 拓展保留使用。
3000–3999-可以由库或框架使用。 不应由应用使用。 可以在 IANA 注册, 先到先得。
4000–4999-可以由应用使用。

七、nginx配置

地址:wss://txw.lsh.cn:8011/websocket/1

map $http_upgrade $upgrade {

        default upgrade;

        '' close;

}

location /websocket {

        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;

        proxy_set_header Connection "upgrade";

        proxy_pass http://websocket;

        proxy_connect_timeout 86400s;

        proxy_read_timeout 86400s;

        proxy_send_timeout 86400s;

}

upstream websocket {

        server 10.84.97.192:8080;

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值