HTML5的Websocket(理论篇 I)
** 先请来TA的邻居:**
http:无状态、基于tcp请求/响应模式的应用层协议 (A:哎呀,上次你请我吃饭了么? B:我想想, 上次请你吃了么) tcp:面向连接、保证高可靠性(数据无丢失、数据无失序、数据无错误、数据无重复到达) 传输层协议。(看啊,大阅兵,如此规整有秩序)
为什么要引入Websocket:
RFC开篇介绍:本协议的目的是为了解决基于浏览器的程序需要拉取资源时必须发起多个HTTP请求和长时间的轮询的问题。
long poll(长轮询): 客户端发送一个request后,服务器拿到这个连接,如果有消息,才返回response给客户端。没有消息,就一直不返回response。之后客户端再次发送request, 重复上次的动作。
从上可以看出,http协议的特点是服务器不能主动联系客户端,只能由客户端发起。它的被动性预示了在完成双向通信时需要不停的连接或连接一直打开,这就需要服务器快速的处理速度或高并发的能力,是非常消耗资源的。
这个时候,Websocket出现了。
Websocket是什么:
RFC中写到:WebSocket协议使在控制环境下运行不受信任代码的客户端和能够选择与那些代码通信的远程主机之间能够双向通信。
对,划重点:双向通信
Websocket在连接之后,客户端可以主动发送消息给服务器,服务器也可以主动向客户端推送消息。比如:预订车票信息,除了我们发请求询问车票如何,当然更希望如果有新消息,可以直接通知我们。
其特点:
(1)握手阶段采用 HTTP 协议,默认端口是80和443
(2)建立在TCP协议基础之上,和http协议同属于应用层
(4)可以发送文本,也可以发送二进制数据
(5)没有同源限制,客户端可以与任意服务器通信
(6)协议标识符是ws(如果加密,为wss),如ws://localhost:8023
简单来说,Websocket协议分为两部分:握手和数据传输。
Websocket API:
这里是指客户端 API。
WebSocket 构造函数
通过调用WebSocket构造函数来创建一个WebSocket实例对象,建立客户端与服务器的连接。
const ws = new WebSocket('ws://localhost:8023');
Websocket事件
WebSocket 是纯事件驱动,通过监听事件可以处理到来的数据和改变的连接状态。服务端发送数据后,消息和事件会异步到达。
-
open:
服务端响应WebSocket连接请求,就会触发open事件。onopen是响应的回调函数。
// 连接请求open事件处理:
ws.onopen = e => {
console.log('Connection success');
ws.send(`Hello ${e}`);
};
如果要指定多个回调函数,可以使用addEventListener方法。
ws.addEventListener('open', e => {
ws.send(`Hello ${e}`);
});
当open事件触发时,意味着握手阶段已结束。服务端已经处理了连接的请求,可以准备收发数据。
-
Message:
收到服务器数据,会触发消息事件,onmessage是响应的回调函数。如下:
// 接受文本消息的事件处理:
ws.onmessage = e => {
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);
}
};
服务器数据可能是文本,也可能是二进制数据,有Blob和ArrayBuffer两种类型,在读取到数据之前需要决定好数据的类型。
-
Error
发生错误会触发error事件, onerror是响应的回调函数, 会导致连接关闭。
//异常处理
ws.onerror = e => {
console.log("WebSocket Error: " , e);
handleErrors(e);
};
-
Close
当连接关闭时触发close事件,对应onclose方法,连接关闭之后,服务端和客户端就不能再通信。
WebSocket 规范中定义了ping 帧 和pong 帧,可以用来做心跳重连,网络状态查询等,但是目前 浏览器只会自动发送pong帧,而不会发ping 帧。(有兴趣可详查ping和pong帧)
//关闭连接处理
ws.onclose = e => {
const code = e.code;
const reason = e.reason;
console.log("Connection close", code, reason);
};
WebSocket 方法:
WebSocket 对象有两个方法:send 和 close
-
send:
客户端和服务器建立连接后,可以调用send方法去发送消息。
//发送一个文本消息
ws.send("this is websocket");
在open事件的回调中调用send()方法传送数据:
const ws = new WebSocket('ws://localhost:8023');
ws.onopen = e => {
console.log('Connection success');
ws.send(`Hello ${e}`);
};
如果想通过响应其他事件发送消息,可通过判断当前的Websocket的readyState属性。接下来会说到readyState.
-
close
close方法用来关闭连接。调用close方法后,将不能发送数据。close方法可以传入两个可选的参数,code 和reason, 以告诉服务端为什么终止连接。
ws.close(); //1000是状态码,代表正常结束。
ws.close(1000, "Closing normally");
WebSocket 属性
- readyState:
readyState值表示连接状态,是只读属性。它有以下四个值:
WebSocket.CONNECTING :连接正在进行,但还没有建立 WebSocket.OPEN :连接已经建立,可以发送消息 WebSocket.CLOSING :连接正在进行关闭握手 WebSocket.CLOSED :连接已经关闭或不能打开
除了在open事件回调中调用send方法,可通过判断readyState值来发送消息。
function bindEventHandler(data) {
if (ws.readyState === WebSocket.OPEN) {
ws.send(data);
} else {
//do something
}
}
-
bufferedAmount:
当客户端传输大量数据时,浏览器会缓存将要流出的数据,bufferedAmount属性可判断有多少字节的二进制数据没有发送出去,发送是否结束。
ws.onopen = function () {
setInterval( function() {
//缓存未满的时候发送
if (ws.bufferedAmount < 1024 * 5) {
ws.send(data);
}
}, 2000);
};
-
protocol:
protocol代表客户端使用的WebSocket协议。当握手协议未成功,这个属性是空。
** 接下来,我们说说握手阶段过程。**
当我们创建Websocket实例对象与服务器建立连接时,
const ws = new WebSocket('ws://localhost:8023');
首先客户端向服务器发起一个握手请求,其请求报文的内容如下:
GET /game HTTP/1.1
Host: 10.242.17.102:8023
Cache-Control: no-cache
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: game
Sec-WebSocket-Version: 10
Origin: http://192.168.185.16
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
从请求头中可以看出,其实是一个基于http的握手请求。与通常的http请求不同的是,增加了一些头信息。
- Upgrade字段: 通知服务器,现在要使用一个升级版协议 - Websocket。
- Sec-WebSocket-Key: 是一个Base64编码的值,这个是浏览器随机生成,通知服务器,需要验证下是否可以进行Websocket通信
- Sec_WebSocket-Protocol: 是用户自定义的字符串,用来标识服务所需要的协议
- Sec-WebSocket-Version: 通知服务器所使用的协议版本
服务器响应:
当服务器返回以下内容,就表示已经接受客户端请求啦,可以建立Websocket通信啦。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: SIEylb7zRYJAEgiqJXaOW3V+ZWQ=
- 101 状态码,表示要转换协议啦
- Upgrde: 通知客户端将要升级成Websocket协议
- Sec-WebSocket-Accept: 经过服务器确认,并且加密过后的 Sec-WebSocket-Key。用来证明客户端和服务器之间能进行通信了。
至此,客户端和服务器握手成功建立了Websocket连接,通信不再使用http数据帧,而采用Websocket独立的数据帧。
以上是Websocket协议的基础理论篇I, 欢迎小伙伴儿们接力(理论篇II, 实战篇神马的), 一起学习一起积累~
如果你喜欢我们的文章,关注我们的公众号和我们互动吧。
HTML5的Websocket(理论篇 I)的更多相关文章
-
认识WebSocket理论篇
本文转自http://www.ibm.com/developerworks/cn/java/j-lo-WebSocket/ HTML5作为下一代WEB标准,拥有许多引人注目的新特性,如Canvas.本 ...
-
认识HTML5的WebSocket
在HTML5规范中,我最喜欢的Web技术就是正迅速变得流行的WebSocket API.WebSocket提供了一个受欢迎的技术,以替代我们过去几年一直在用的Ajax技术.这个新的API提供了一个方法 ...
-
RabbitMQ学习总结 第一篇:理论篇
目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...
-
HTML5之WebSocket
在HTML5规范中,我最喜欢的Web技术就是正迅速变得流行的WebSocket API.WebSocket提供了一个受欢迎的技术,以替代我们过去几年一直在用的Ajax技术.这个新的API提供了一个方法 ...
-
【PHPsocket编程专题(理论篇)】初步理解TCP/IP、Http、Socket.md
前言 我们平时说的最多的socket是什么呢,实际上socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API).那TCP/IP又是什么呢?TCP/IP是ISO/OS ...
-
Lucene核心--构建Lucene搜索(上篇,理论篇)
2.1构建Lucene搜索 2.1.1 Lucene内容模型 一个文档(document)就是Lucene建立索引和搜索的原子单元,它由一个或者多个字段(field)组成,字段才是Lucene的真实内 ...
-
游戏UI框架设计(一) : 架构设计理论篇
游戏UI框架设计(一) ---架构设计理论篇 前几天(2017年2月)看到一篇文章,国内王健林.马云等大咖们看好的未来十大最有"钱途"产业中,排名第一的就是"泛娱乐&qu ...
-
HTML5 的WebSocket
认识HTML5的WebSocket
-
使用Html5下WebSocket搭建简易聊天室
一.Html5WebSocket介绍 WebSocket protocol 是HTML5一种新的协议(protocol).它是实现了浏览器与服务器全双工通信(full-duplex). 现在,很多网站 ...
随机推荐
- js总结1
-
c# 4.0新特性一览
原文:http://www.cnblogs.com/palo/archive/2009/03/01/1400949.html 终于静下心来仔细听了一遍Anders Hejlsberg(Visual S ...
-
WINDOWS系统下环境变量PATH和CLASSPATH的意思
1 PATH 对于没有包含路径的命令,WINDOWS系统会默认去Windows 目录(C:\windows)和系统目录(C:\windows\system32)查找,如果没有找到,就去PATH变量内包 ...
-
MongoDB 安装和配置
[前言] Mongodb是一款nosql数据库,关于nosql 以及 mongodb本文不进行介绍,在数据库的选型方面,本人说是在机缘巧合之下选择了mongodb,并且拟使用mongodb搭建日志系统 ...
-
vue的条件渲染和列表渲染介绍
一.条件渲染 1.v-if语句 <div v-if="seen">hahahah</div> <!-- v-if插入或者删除元素的指令 --> ...
-
python3爬虫一
1.环境安装: 在py3env(虚拟环境)下安装scrapy,新建项目: pip install scrapy scrapy startproject ArticleSpider cd Article ...
-
0_Simple__simpleOccupancy
计算核函数调用使得占用率,并尝试使用 runtime 函数自动优化线程块尺寸,以便提高占用率. ▶ 源代码. #include <iostream> #include "cuda ...
-
[Javascript] Coding interview problem: Scheduler functional way
Implement a job scheduler which takes in a function f and an integer n, and calls f after nmilliseco ...
-
Android获取屏幕高度、标题高度、状态栏高度详解
Android获取屏幕高度的方法主要由view提供 通过View提供的方法获取高度方式有两种: 1, 当前显示的view中直接获取当前view高宽2,通过Activity的getWindow().fi ...
-
ASP.NET MVC4 异常拦截
ASP.NET MVC4 程序发生异常时,通过拦截Action的异常,重写ActionFilterAttribute 的方法OnActionExecuted实现. 具体实现代码如下: /// < ...