websocket详解

之前利用websocket以及jQuery做了一个聊天通讯应用,最近在总结整个过程中的一些问题,也借此机会聊聊websocket协议。

webSocket本身不存在跨域问题,所以可以利用webSocket来进行非同源之间的通信。

webSocket协议

传统的http协议有着一个缺陷:其模型是客户端请求,服务器响应的形式,并且连接完之后就断开,这种就造成了一个问题,服务端可不可以在实现长连接的同时,让响应将数据发送呢?诚然,目前http2.0也推出了服务器推送的功能,但是目前http2.0并未完全取代http1.1。由于上面的问题,webSocket协议就应运而生。

webSocket协议与http协议

Webscoket是Web浏览器和服务器之间的一种全双工通信协议,与http协议相比

共同点:
1、都是基于TCP协议的;
2、都是客户端-服务器模型;
3、默认端口都是80或者443(ws,http:80,wss,https:443;)
4、webSocket协议是基于http的;(个人观点:我并不确定这个说法是否准确,但是我个人感觉可以这样说)
不同点:
1、webSocket协议可以服务器主动推数据;(最大的特点)
2、没有同源限制;
3、数据格式多、效率高;
4

这里主要说一下,我上面说的第4点共同点,我主要是从webSocket协议的报文角度出发得到的这个观点,下面来看看这个例子:

客户端请求:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

服务器响应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

根据客户端请求,我们可以看出实际上发出的还是http请求,但是在http握手完成后,由于请求中携带着Upgrade、Connection字段会将http协议升级成webSocket协议。在响应中,状态码以及响应字符串分别是101、Switching Protocols。另外,需要注意的是Sec-WebSocket-Key字段是很重要的,目前还没整理完,后续慢慢补上。
基于上面的分析,个人觉得webSocket协议是基于http的。

心跳检测与重连机制

由于webSocket是面向客户端与服务端且双方可以互相发送数据,那么保持连接没有断开是极为重要的一点。webSocket利用心跳检测来判断连接状态,如果发生了断开,那么就启用重连机制,让客户端-服务器继续保持连接。
心跳检测:每隔一个时间,发一次消息,检测连接状态。
先来上一段代码,后面再做分析

<html>
<head>
  <meta charset="utf-8">
  <title>WebSocket Demo</title>
</head>
<body>
  <script type="text/javascript">
    var lockReconnect = false;//避免重复连接
    var url = "http://localhost:3000";
    var ws;
    var tt;
    function createWebSocket() {
      try {
        socket = io(url);
        init();
      } catch(e) {
        reconnect(url);
      }
    }
    function init() {
      socket.onclose = function () {
        reconnect(url);
      };
      socket.onerror = function() {
        reconnect(url);
      };
      socket.onopen = function () {
        //心跳检测重置
        heartCheck.start();
      };
      socket.onmessage = function (e) {
        //拿到任何消息都说明当前连接是正常的
        console.log('接收到消息');
        heartCheck.start();
      }
    }
    
    function reconnect(url) {
      if(lockReconnect) {
        return;
      };
      lockReconnect = true;
      //没连接上会一直重连,设置延迟避免请求过多
      if(tt){clearTimeout(tt)}
      tt = setTimeout(function () {
        createWebSocket(url);
        lockReconnect = false;
      }, 3000);
    }
    //心跳检测
    var heartCheck = {
      timeout: 3000,
      timer : null,
      serverTimeoutObj: null,
      start: function(){
        var self = this;
        this.timer && clearTimeout(this.timer );
        this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
        this.timer = setTimeout(function(){
          //心跳消息,后端收到返回心跳消息,
          socket.send("HeartBeat");
          self.serverTimeoutObj = setTimeout(function() {
            socket.close()
            // 超时重连
          }, self.timeout);
        }, this.timeout)
      }
    }
    createWebSocket(url);
  </script>
</body>
</html>

首先,我们分析一下连接断开的原因

1、正常断开,利用监听close函数,可以进行重连;
2、报错断开,利用监听error函数,可以进行重连;
3、非正常断开,比如网络问题,前端问题或者后端问题,都会造成一个结果,那就是发出消息无法收到回应,这就是心跳检测的原理。当一方发出消息之后,另一方必须做出回应,通过message进行监听,如果没有收到消息或者消息超时,则默认连接断开,调用close函数,而websocket监听到close函数,立即重新连接。如果收到消息直接重新计时。

未完待续~~~~


参考文章:
掘金:前端必备 HTTP 技能之 WebSocket 协议详解
思否:理解WebSocket心跳及重连机制(五)

你可能感兴趣的:(websocket,socket,网络协议,html5,reactjs)