什么是WebSocket?php
WebSocket是HTML5开始提供的一种在TCP链接上进行全双工通信的协议,是一种服务器推送技术。html
WebSocket出现以前客户端如何获取服务端的实时数据?html5
Comet:是一种服务器向页面推送数据的技术。有如下实现方式:node
(1) ajax轮询:浏览器定时向服务器发送请求,询问服务器是否有新信息。web
(2) 长轮询:客户端发送请求后,服务器会保持链接,直到有新数据返回给客户端或请求超时。客户端收到数据并处理完,或者请求超时后,再向服务端发送新请求。ajax
(3) HTTP流:浏览器向服务器发送一个请求,服务器保持链接打开,而后周期性地向浏览器发送数据。浏览器经过侦听readystatechange
事件及检测readyState
的值是否为3,是则比较此前接收到的数据,决定从收到的数据中的什么位置开始取得最新的数据。小程序
(4) SSE:服务器发送事件,是围绕只读Comet交互推出的API。使用SSE API建立到服务器的单向链接,服务器能够经过这个链接发送任意数量的数据。SSE支持ajax轮询、长轮询和HTTP流,能在断开链接时自动肯定什么时候从新链接。微信小程序
为何须要WebSocket?浏览器
(1) HTTP协议的局限缓存
(2) 轮询、HTTP流、SSE方式存在局限性:
WebSocket是一种与服务器进行全双工、双向通讯的信道,专门为快速传输小数据设计。适用于聊天室等须要双向通讯的场景。
WebSocket
的特色
(1) 双向通讯,服务器能够主动向客户端推送信息,客户端也能够主动向服务器发送信息
(2) 创建在TCP协议之上
(3) 与HTTP协议有着良好的兼容性
(4) 数据格式比较轻量,性能开销小,通讯高效
(5) 能够发送文本,也能够发送二进制数据
(6) 没有同源限制,是否与某个域中的页面通讯,彻底取决于服务器(经过握手信息能够知道请求来自何方)
(7) 协议标识符为ws
或wss
,服务器网址就是URL
WebSocket协议与HTTP协议的联系和区别
(1) 联系
(2)区别
WebSocket | HTTP |
---|---|
是HTML5新增的一种通讯协议 | 与HTML无直接关系 |
双向通讯 | 单向通讯 |
持久链接,整个通信过程创建在一次链接中 | 非持久链接,每次请求要从新创建链接 |
创建WebSocket链接的过程
客户端向服务器发送一个升级协议的HTTP请求,这个请求头部包含Connection
和Upgrade
字段,表示客户端须要使用WebSocket
协议。服务器将HTTP协议升级成WebSocket
协议后返回客户端响应数据,即完成了握手阶段,创建了WebSocket
链接,这个链接会持续存在,直到客户端或服务器主动关闭链接。
WebSocket的使用
(1) 使用WebSocket
构造函数建立WebSocket
对象
var ws = new WebSocket('wss://wx.douyucdn.cn')
复制代码
(2) 添加事件处理程序
ws.onopen = function() {
// 调用send()方法发送数据
ws.send('发送数据');
}
ws.onmessage = function(event) {
// 处理接收到的数据
var receive_msg = event.data;
}
ws.onerror = function() {
// 出错处理
ws.close();
}
ws.onclose = function() {
// 关闭WebSocket
}
复制代码
WebSocket的应用
双向通讯,如聊天室。
(1) 微信小程序对WebSocket
进行了封装,wx.connectSocket()
能够理解为建立了一个WebSocket
实例SocketTask
。
(2) socket.io
支持WebSocket
、轮询、HTTP流等方式。
WebSocket的降级方案
WebSocket
协议不一样于HTTP
,须要创建和维护WebSocket
服务器。若是现有服务器不能用于WebSocket
通讯,能够组合使用XHR
和SSE
实现双向通讯。【WebSocket
至关于在SSE
的基础上增长了send()
方法】
详解:
HTTP流的实现:
服务端
<?php
$i = 0;
while(true) {
// 输出一些数据,而后当即刷新输出缓存
echo "Number is $i";
flush();
// 等待几秒钟
sleep(10);
$i++;
}
?>
复制代码
浏览器
function createStreamingClient(url, progress, finished){
var xhr = new XMLHttpRequest(),
received = 0;
xhr.open("get", url, true);
xhr.onreadystatechange = function(){
var result;
if (xhr.readyState == 3){
//只取得最新数据并调整计数器
result = xhr.responseText.substring(received);
received += result.length;
//调用 progress 回调函数
progress(result);
} else if (xhr.readyState == 4){
finished(xhr.responseText);
}
};
xhr.send(null);
return xhr;
}
var client = createStreamingClient("streaming.php", function(data){
alert("Received: " + data);
}, function(data){
alert("Done!");
});
复制代码
SSE API
(1) 建立一个EventSource
对象
var source = new EventSource('myevents.php');
复制代码
(2) 添加事件处理程序
source.onopen = function() {}
source.onmessage = function(event) {
// 处理数据
var data = event.data;
}
source.onerror = function() {
// 出错处理
source.close();
}
复制代码
(3) 属性
readyState
属性:链接的状态
(4) 方法
注:SSE方式服务器返回的数据是流信息,响应的MIME
类型必须是text/event-stream
,即设置响应头部:
Content-Type: text/event-stream
复制代码
HTTP与WebSocket的生命周期
WebSocket握手的请求头和响应头
请求中的header:
Connection: Upgrade
:指示这是一个升级请求Upgrade: websocket
:表示升级为websocket
协议Sec-WebSocket-Key
:向服务器提供所需的信息,确认客户端有权请求升级到WebSocket
,防止滥用。此头部由客户端自动生成,没法经过XMLHttpRequest.setRequestHeader()
方法添加。Sec-WebSocket-Protocol
:以优先顺序指定客户端要使用的一个或多个协议Sec-WebSocket-Version
:指定客户端但愿使用的WebSocket
协议版本Sec-WebSocket-Extensions
:指定要求服务器使用的一个或多个WebSocke
t扩展服务端响应中的header:
Connection: Upgrade
Upgrade: websocket
:和Connection
一块儿表示服务器已成功切换协议Sec-WebSocket-Accept
:返回根据请求头中Sec-WebSocket-Key
字段值生成的值Sec-WebSocket-Protocol
:返回客户端指定使用的全部协议中支持的第一个协议Sec-WebSocket-Version
:服务器若是支持客户端要求的协议版本,则响应头中不包含这个字段。不然,服务端将返回一个错误,并在响应头中以此字段返回服务器支持的协议列表Sec-WebSocket-Extensions
:MDN文档中没有明确指明,私觉得与Sec-WebSocket-Version
类似WebSocket API
(1) 使用构造函数建立WebSocket
对象
var socket = new WebSocket(url, [protocol]); // protocol指定了可接收的子协议
复制代码
(2) 属性
WebSocket.readyState
:返回实例对象的当前状态
WebSocket.CONNECTING
,正在链接WebSocket.OPEN
,链接成功WebSocket.CLOSING
,正在关闭链接WebSocket.CLOSED
,链接关闭,或打开链接失败WebSocket.bufferedAmount
:表示队列中等待传输的UTF-8
字节数WebSocket.onopen
WebSocket.onmessage
WebSocket.onerror
WebSocket.onclose
WebSocket.binaryType
:WebSocket.protocol
WebSocket.url
(3) 事件
事件 | 事件处理程序 | 描述 |
---|---|---|
open | Socket.onopen | 链接创建时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通讯发生错误时触发 |
close | Socket.onclose | 链接关闭时触发 |
(4) 方法
WebSocket.send(data)
:发送数据
WebSocket.close
:关闭链接
WebSocket在项目中的应用:
tcp/TcpClient.js
使用wx.connectSocket
返回WebSocket
实例SocketTask
@shark/net/lib/tcp/webSocket.js
直接调用WebSocket
构造函数建立WebSocket
实例参考:
【阮一峰】WebSocket教程:www.ruanyifeng.com/blog/2017/0…
【知乎】WebSocket是什么原理?为何能够实现持久链接?www.zhihu.com/question/20…
【掘金】WebSocket介绍以及node+socket-io实现聊天室功能:juejin.im/entry/5ab37…
【MDN】协议升级机制:developer.mozilla.org/zh-CN/docs/…
【MDN】WebSocket:developer.mozilla.org/en-US/docs/…
【菜鸟教程】HTML5 WebSocket:www.runoob.com/html/html5-…
【HTML5】全双工通讯的WebSocket:halfrost.com/websocket/
【socket.io】socket.io:socket.io/get-started…
【JavaScript高级程序设计】第21章21.5节