WebSocket

WebSocket

1. WebSocket 理解

1.1 WebSocket出现的原因

我们已经有了 HTTP 协议,为什么还需要另一个协议?

因为 HTTP 协议有一个缺陷:通信只能由客户端发起。

这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。因此我们只能使用"轮询", 也就是每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。

<body>
  <script>
    //http是单向的,要东西才会给
     setInterval(() => {
      $.ajax({   //每隔10s向后台请求数据,这就是轮询
        ...
      })
    }, 10000)
  </script>
</body>

然而轮询的效率比较低, 非常 浪费资源。轮询的缺陷--后台数据没变,间隔响应时间还会请求数据

因此为了更好地处理这种问题.WebSocket就 这样被发明了

1.2 WebSocket 简介

WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

特点 :
  1. 建立在 TCP 协议之上,服务器端的实现比较容易。

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

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

  4. 可以发送文本,也可以发送二进制数据。

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

  6. 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

ws://example.com:80/some/path

2. 客户端API

2.1 WebSocket 构造函数

WebSocket 对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的 API。

对于我们来时通过WebSocket构造函数实例化WebSocket对象, 在实例化过程中连接服务器

语法;
var aWebSocket = new WebSocket(url);
参数:
  1. url: 要连接的URL;这应该是WebSocket服务器将响应的URL

例子:

let ws = new WebSocket('ws://www.localhost:8080')在关闭
4. CLOSED: 值为3, 表示连
2.2 webSocket.readyState

实例的readyState 属性返回实例对象的当前状态, 共有四种状态

  1. CONNECTING: 值为0, 表示正在连接
  2. OPEN: 值为1, 表示连接成功, 可以通信了
  3. CLOSING: 值为2, 表示连接正接已经关闭, 或者 打开连接失败
switch (ws.readyState) {
  case WebSocket.CONNECTING:
    break;
  case WebSocket.OPEN:
    break;
  case WebSocket.CLOSING:
    break;
  case WebSocket.CLOSED:
    break;
  default:
    break;
}
3 webSocket.onopen

实例对象的onopen 方法, 用于执行连接成功后的回调函数

// socket 连接成功后触发事件
ws.onopen = function(){
   // 像后端发送数据 
    ws.send("Hello Word")
}

如果需要指定多个回调函数, 可以使用addEventListener事件绑定

ws.addEventListener('open', function (ev) {
   ws.send('Hello Server!');
});
ws.addEventListener('open', function (ev) {
   ws.send('你好');
});
2.4 webSocket.send()

实例对象的send()方法用于向服务器发送数据。

发送文本数据

ws.send('hello word');

发送JSON数据

ws.send(JSON.stringify({name:'张三'}));
2.5 webSocket.onmessage

实例对象的onmessage属性,用于指定收到服务器数据后的回调函数。

ws.onmessage = function(ev) {
  var data = ev.data;
  // 处理数据
};

ws.addEventListener("message", function(ev) {
  var data = ev.data;
  // 处理数据
});
2.6 webSocket.onclose

实例对象的onclose 属性, 指定连接关闭后的回调函数

注意: socket连接失败也会触发onclose事件

ws.onclose = function(ev) {
  console.log('关闭socket连接', ev)
};

ws.addEventListener("close", function(event) {
  console.log('关闭socket连接', ev)
});
2.7 webSocket.onerror

实例对象的onerror属性,用于指定报错时的回调函数。

socket.onerror = function(ev) {
  // 处理错误
};

socket.addEventListener("error", function(ev) {
  // 处理错误
});

3. WebSocket 封装

class JsSocket {

    /**
       *  构造方法, 进行初始化
       *  @param {String} url socket 连接地址
       * */
    constructor(url) {
        this.url = url;
        this.lockReconnect = false;
        this.reconnectCount = 0
    }

    /**
       * 开始连接
       * @params { Function } callback  
       * */
    connect(callback) {
        this.callback = callback;
        this.disconnect()

        try {
            console.log("JsSocket开始连接...", this.url)
            this.ws = new WebSocket(this.url)

            this.ws.onopen = function(ev) {
                console.log("JsSocket onpen...", ev)
                this.reconnectTimes = 0
            }

            this.ws.onmessage = function(ev) {
                console.log("JsSocket onmessage...", ev)
                let data = ev.data;
                if (!data) {
                    data = JSON.parse(data)
                }


                callback(data)
            }

            this.ws.onclose = (ev) => {
                console.log("JsSocket onclose...", ev)
                this.reconnect()
            }

            this.ws.onerror = (ev) => {
                console.log("JsSocket onerror...", ev)
                this.reconnect()
            }
        } catch (error) {
            console.log("JsSocket", error)
        }
    }


    /**
       * 断开连接
       * */
    disconnect() {
        if (this.ws) {
            this.ws.onclose = null;
            this.ws.close()
            this.ws = null
        }
    }


    /**
       * 发送消息
       * @params { Object } data 消息内容
       * */
    send(data) {
        if (this.ws) {
            this.ws.send(data)
        }
    }


    /**
       * 重新连接
       * */
    reconnect() {
        if (this.lockReconnect || this.reconnectCount > 5) {
            console.log('JsSocket 重连锁定 或者 超过重连次数')
            return;
        }
        this.lockReconnect = true;
        setTimeout(() => {
            this.reconnectCount++;
            console.log('JsSocket 重连...')
            this.connect(this.callback)
            this.lockReconnect = false
        }, 3000)
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容