HTML5的Websocket(理论篇 I)

By admin in 计算机教程 on 2019年2月16日

HTML5的Websocket(理论篇 I)

2017/10/28 · HTML5 ·
websocket

原文出处:
转转前端   

先请来TA的邻居:

http:无状态、基于tcp请求/响应模式的应用层协议
(A:哎呀,上次你请我吃饭了么? B:我想想, 上次请你吃了么)
tcp:面向连接、保证高可靠性(数据无丢失、数据无失序、数据无错误、数据无重复到达)
传输层协议。(看啊,大阅兵,如此规整有秩序)

为什么要引入Websocket:

RFC开篇介绍:本协议的目的是为了解决基于浏览器的程序需要拉取资源时必须发起多个HTTP请求和长时间的轮询的问题。

long poll(长轮询):
客户端发送一个request后,服务器拿到这个连接,如果有消息,才返回response给客户端。没有消息,就一直不返回response。之后客户端再次发送request,
重复上次的动作。

澳门金沙30064在线网站 1

从上可以看出,http协议的特点是服务器不能主动联系客户端,只能由客户端发起。它的被动性预示了在完成双向通信时需要不停的连接或连接一直打开,这就需要服务器快速的处理速度或高并发的能力,是非常消耗资源的。

这个时候,Websocket出现了。

原文出处:
转转前端   

Websocket是什么:

RFC中写到:WebSocket协议使在控制环境下运行不受信任代码的客户端和能够选择与那些代码通信的远程主机之间能够双向通信。

对,划重点:双向通信

Websocket在连接之后,客户端可以主动发送消息给服务器,服务器也可以主动向客户端推送消息。比如:预订车票信息,除了我们发请求询问车票如何,当然更希望如果有新消息,可以直接通知我们。

其特点:

(1)握手阶段采用 HTTP 协议,默认端口是80和443

(2)建立在TCP协议基础之上,和http协议同属于应用层

(4)可以发送文本,也可以发送二进制数据

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

(6)协议标识符是ws(如果加密,为wss),如ws://localhost:8023

简单来说,Websocket协议分为两部分:握手和数据传输。

澳门金沙30064在线网站 2

先请来TA的邻居:

http:无状态、基于tcp请求/响应模式的应用层协议
(A:哎呀,上次你请我吃饭了么? B:我想想, 上次请你吃了么)
tcp:面向连接、保证高可靠性(数据无丢失、数据无失序、数据无错误、数据无重复到达)
传输层协议。(看啊,大阅兵,如此规整有秩序)

为什么要引入Websocket:

RFC开篇介绍:本协议的目的是为了解决基于浏览器的程序需要拉取资源时必须发起多个HTTP请求和长时间的轮询的问题。

Websocket API:

这里是指客户端 API。

long poll(长轮询):
客户端发送一个request后,服务器拿到这个连接,如果有消息,才返回response给客户端。没有消息,就一直不返回response。之后客户端再次发送request,
重复上次的动作。

WebSocket 构造函数

通过调用WebSocket构造函数来创建一个WebSocket实例对象,建立客户端与服务器的连接。

JavaScript

const ws = new WebSocket(‘ws://localhost:8023’);

1
const ws = new WebSocket(‘ws://localhost:8023’);

澳门金沙30064在线网站 3

Websocket事件

WebSocket 是纯事件驱动,通过监听事件可以处理到来的数据和改变的连接状态。服务端发送数据后,消息和事件会异步到达。

  • open:
    服务端响应WebSocket连接请求,就会触发open事件。onopen是响应的回调函数。
JavaScript

// 连接请求open事件处理: ws.onopen = e => {
console.log('Connection success'); ws.send(\`Hello ${e}\`); };

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f447934b5b531196143-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b5b531196143-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f447934b5b531196143-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b5b531196143-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f447934b5b531196143-5">
5
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f447934b5b531196143-1" class="crayon-line">
 // 连接请求open事件处理:
</div>
<div id="crayon-5b8f447934b5b531196143-2" class="crayon-line crayon-striped-line">
     ws.onopen = e =&gt; {
</div>
<div id="crayon-5b8f447934b5b531196143-3" class="crayon-line">
         console.log('Connection success');
</div>
<div id="crayon-5b8f447934b5b531196143-4" class="crayon-line crayon-striped-line">
         ws.send(`Hello ${e}`);
</div>
<div id="crayon-5b8f447934b5b531196143-5" class="crayon-line">
     };
</div>
</div></td>
</tr>
</tbody>
</table>

如果要指定多个回调函数,可以使用addEventListener方法。

JavaScript

ws.addEventListener(‘open’, e => { ws.send(`澳门金沙30064在线网站,Hello ${e}`); });

1
2
3
ws.addEventListener(‘open’, e => {
  ws.send(`Hello ${e}`);
});

当open事件触发时,意味着握手阶段已结束。服务端已经处理了连接的请求,可以准备收发数据。

  • Message:收到服务器数据,会触发消息事件,onmessage是响应的回调函数。如下:
JavaScript

// 接受文本消息的事件处理: ws.onmessage = e =&gt; { const data =
e.data; if (typeof data === "string") { console.log("Received string
message ",data); } else if (data instanceof Blob) {
console.log("Received blob message ", data); } };

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f447934b62129912854-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b62129912854-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f447934b62129912854-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b62129912854-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f447934b62129912854-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b62129912854-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f447934b62129912854-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b62129912854-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f447934b62129912854-9">
9
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f447934b62129912854-1" class="crayon-line">
// 接受文本消息的事件处理:
</div>
<div id="crayon-5b8f447934b62129912854-2" class="crayon-line crayon-striped-line">
ws.onmessage = e =&gt; {
</div>
<div id="crayon-5b8f447934b62129912854-3" class="crayon-line">
    const data = e.data;
</div>
<div id="crayon-5b8f447934b62129912854-4" class="crayon-line crayon-striped-line">
    if (typeof data === &quot;string&quot;) {
</div>
<div id="crayon-5b8f447934b62129912854-5" class="crayon-line">
        console.log(&quot;Received string message &quot;,data);
</div>
<div id="crayon-5b8f447934b62129912854-6" class="crayon-line crayon-striped-line">
    } else if (data instanceof Blob) {
</div>
<div id="crayon-5b8f447934b62129912854-7" class="crayon-line">
        console.log(&quot;Received blob message &quot;, data);
</div>
<div id="crayon-5b8f447934b62129912854-8" class="crayon-line crayon-striped-line">
    }
</div>
<div id="crayon-5b8f447934b62129912854-9" class="crayon-line">
};
</div>
</div></td>
</tr>
</tbody>
</table>

服务器数据可能是文本,也可能是二进制数据,有Blob和ArrayBuffer两种类型,在读取到数据之前需要决定好数据的类型。

  • Error发生错误会触发error事件, onerror是响应的回调函数,
    会导致连接关闭。
JavaScript

//异常处理 ws.onerror = e =&gt; { console.log("WebSocket Error: " ,
e); handleErrors(e); };

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f447934b66862080563-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b66862080563-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f447934b66862080563-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b66862080563-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f447934b66862080563-5">
5
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f447934b66862080563-1" class="crayon-line">
//异常处理
</div>
<div id="crayon-5b8f447934b66862080563-2" class="crayon-line crayon-striped-line">
ws.onerror = e =&gt; {
</div>
<div id="crayon-5b8f447934b66862080563-3" class="crayon-line">
    console.log(&quot;WebSocket Error: &quot; , e);
</div>
<div id="crayon-5b8f447934b66862080563-4" class="crayon-line crayon-striped-line">
    handleErrors(e);
</div>
<div id="crayon-5b8f447934b66862080563-5" class="crayon-line">
};
</div>
</div></td>
</tr>
</tbody>
</table>

  • Close当连接关闭时触发close事件,对应onclose方法,连接关闭之后,服务端和客户端就不能再通信。

WebSocket 规范中定义了ping 帧 和pong
帧,可以用来做心跳重连,网络状态查询等,但是目前
浏览器只会自动发送pong帧,而不会发ping 帧。(有兴趣可详查ping和pong帧)

JavaScript

//关闭连接处理 ws.onclose = e => { const code = e.code; const reason
= e.reason; console.log(“Connection close”, code, reason); };

1
2
3
4
5
6
//关闭连接处理
ws.onclose = e => {
    const code = e.code;
    const reason = e.reason;
    console.log("Connection close", code, reason);
};

从上可以看出,http协议的特点是服务器不能主动联系客户端,只能由客户端发起。它的被动性预示了在完成双向通信时需要不停的连接或连接一直打开,这就需要服务器快速的处理速度或高并发的能力,是非常消耗资源的。

WebSocket 方法:

WebSocket 对象有两个方法:send 和 close

  • send:客户端和服务器建立连接后,可以调用send方法去发送消息。
JavaScript

//发送一个文本消息 ws.send("this is websocket");

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f447934b6d916593124-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b6d916593124-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f447934b6d916593124-1" class="crayon-line">
//发送一个文本消息
</div>
<div id="crayon-5b8f447934b6d916593124-2" class="crayon-line crayon-striped-line">
ws.send(&quot;this is websocket&quot;);
</div>
</div></td>
</tr>
</tbody>
</table>

在open事件的回调中调用send()方法传送数据:

JavaScript

const ws = new WebSocket(‘ws://localhost:8023’); ws.onopen = e => {
console.log(‘Connection success’); ws.send(`Hello ${e}`); };

1
2
3
4
5
const ws = new WebSocket(‘ws://localhost:8023’);
ws.onopen = e => {
    console.log(‘Connection success’);
    ws.send(`Hello ${e}`);
};

如果想通过响应其他事件发送消息,可通过判断当前的Websocket的readyState属性。接下来会说到readyState.

  • closeclose方法用来关闭连接。调用close方法后,将不能发送数据。close方法可以传入两个可选的参数,code
    和reason, 以告诉服务端为什么终止连接。
JavaScript

ws.close(); //1000是状态码,代表正常结束。 ws.close(1000, "Closing
normally");

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f447934b73487491254-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b73487491254-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f447934b73487491254-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f447934b73487491254-4">
4
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f447934b73487491254-1" class="crayon-line">
ws.close();
</div>
<div id="crayon-5b8f447934b73487491254-2" class="crayon-line crayon-striped-line">
 
</div>
<div id="crayon-5b8f447934b73487491254-3" class="crayon-line">
//1000是状态码,代表正常结束。
</div>
<div id="crayon-5b8f447934b73487491254-4" class="crayon-line crayon-striped-line">
ws.close(1000, &quot;Closing normally&quot;);
</div>
</div></td>
</tr>
</tbody>
</table>

这个时候,Websocket出现了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 澳门金沙30064在线网站 版权所有