一.什么是WebSocket
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工(full-duplex)通讯的协议。没有了 Request 和 Response 的概念,两者地位完全平等,连接一旦建立,就建立了真持久性连接,双方可以通过WebSocket随时向对方发送数据。
WebSocket有如下特性:
- 伴随着HTML5而出现
- Web端的Socket, 服务器端和客户端可相互发送消息
- 本质上是TCP连接
- 为解决客户端与服务端实时通信而产生的技术
注:WebSocket长连接需要基于Ping/Pong心跳机制来维持。
现有的用于服务器和客户端之间的双工通信技术:
- 轮询(Polling):
客户端每隔固定时间向后台发送一次请求,询问服务器是否有新数据。
缺点:
1.延迟,需要固定的轮询时间,不一定是实时数据。
2.大量耗费服务器内存和宽带资源,因为不停的请求服务器,很多时候 并没有新的数据更新,因此绝大部分请求都是无效请求。 - 长轮询(Long Polling):
客户端发送 HTTP 给服务器之后,有没有新消息,如果没有新消息,就一直等待。直到有消息或者超时了,才会返回给客户端。消息返回后,客户端再次建立连接,如此反复。
优点:在某种程度上减小了网络带宽和 CPU 利用率等问题。
缺点:
1.如果是高实时的系统,肯定不会采用这种办法。因为一个 GET 请求来回需要 2个 RTT,很可能在这段时间内,数据变化很大,客户端拿到的数据已经延后很多了。
2.网络带宽低利用率的问题也没有从根源上解决。每个 Request 都会带相同的 Header。
注:
RTT(Round-Trip Time): 往返时延。在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的 确认(接收端收到数据后便立即发送确认),总共经历的时延RTT(Round-Trip Time): 往返时延。在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的 确认(接收端收到数据后便立即发送确认),总共经历的时延。 - 数据流(Streaming):
服务器保持连接打开并与客户端一起激活,直到并且除非提取所需的数据。在这种情况下,连接是无限期打开的。
缺点:
1.流传输包括HTTP标头,这会增加文件大小,增加延迟。
2.在服务器往客户端推送,这个方向的流实时性比较好。但是依旧是单向的,客户端请求服务器依然还需要一次 HTTP 请求。 - AJAX:
AJAX基于Javascript的 XmlHttpRequest 对象。它是Asynchronous Javascript和XML的缩写形式。XmlHttpRequest 对象允许执行Javascript而无需重新加载完整的网页。AJAX仅发送和接收网页的一部分。
缺点:
1.需要发送HTTP标头,这使数据量更大。
2.是半双工的。
3.服务器消耗更多资源
二.原生WebSocket
WebSocket构造函数,为了建立到服务器的WebSocket连接,使用WebSocket接口,通过指向一个代表所要连接端点的URL,实例化一个WebSocket对象。
WebSocket协议定义了两种URL方案(URL Scheme):
- ws(WebSocket):客户端与服务器之间的非加密流量,与HTTP URI方案类似。
- wss(WebSocket Secure):客户端与服务器之间的加密流量,该方案表示使用传输层安全性(TLS,也叫SSL)的WebSocket连接,使用HTTPS采用的安全机制来保证HTTP连接安全。
WebSocket构造函数的必须参数如下,它必须是以ws://
或者wss://
开始的一个完全限定URL。
如:
let ws = new WebSocket("ws://aaa.com");
//或者是
let ws = new WebSocket("ws://aaa.com", "myProtocol");
//或者是
let ws = new WebSocket("ws://aaa.com", ["myProtocol1", "myProtocol2"]);
连接到WebSocket服务器时,可以选择使用第二个参数列出应用程序支持的协议,用于协议协商。
协议协商对于确定WebSocket服务器支持的协议及版本很有用。应用程序可能支持多个协议,使用协议协商选择与特定服务器通信的协议。
1.WebSocket 事件
事件 | 事件处理程序 | 描述 |
---|---|---|
open | Socket.onopen | 连接建立时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通信发生错误时触发 |
close | Socket.onclose | 连接关闭时触发 |
2.WebSocket 方法
方法 | 描述 |
---|---|
Socket.send(string) | 使用连接发送数据 |
Socket.close(number, string) | 关闭连接 |
二.插件WebSocket: socket.io(服务端)/socket.io-client(客户端)
文档地址:https://socket.io/docs/v4/cli...
客户端NPM安装:
npm install socket.io-client
客户端配置并连接服务器:
import io from "socket.io-client";
const socket = io(
"http://aaa.com",//java后台socket server地址
{
reconnection: true,//是否自动重连
reconnectionDelay: 10 * 1000,//每次重连的延迟
timeout: 10000,//每次重连的时间间隔
reconnectionAttempts: 100,//尝试重连次数
//连接的协议的顺序优先级
transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling']//
});
//其余配置详见文档
客户端监听服务端传递的信息:
console.log(socket.connected); // socket是否与服务器连接
console.log(socket.disconnected); // socket是否与服务器断开连接
socket.open(); // 手动重连
// 连接成功
socket.on("connect", () => {
console.log(socket.id, '监听客户端连接成功-connect');
})
// 断开连接
socket.on("disconnect", (reason) => {
console.log(socket.connected);
console.log("断开连接-disconnect", reason);
})
// 错误
socket.on("error", (err) => {
console.log("错误-error", err);
})
// 连接错误
socket.on("connect_error", (err) => {
err
console.log("连接错误-connect_error");
});
// 连接超时
socket.on("connect_timeout", (data) => {
console.log("连接超时-connect_timeout", data);
});
// 重连成功
socket.on("reconnect", (attemptNumber) => {
// 重连尝试次数
console.log("重连成功-reconnect", attemptNumber)
});
// 尝试重连时触发
socket.on("reconnect_attempt", (attemptNumber) => {
// 重连尝试次数
console.log("尝试重连-reconnect_attempt", attemptNumber)
});
// 在尝试重新连接时触发
socket.on("reconnecting", (attemptNumber) => {
// 重连尝试次数
console.log("正在尝试重连-reconnecting", attemptNumber)
});
// 重连尝试错误
socket.on("reconnect_error", (err) => {
err
console.log(socket.connected);
console.log("重连尝试错误-reconnect_error");
});
// 客户端不能重连时触发
socket.on("reconnect_failed", () => {
console.log("客户端不能连接-reconnect_failed")
});
// 当一个ping被发送到服务器时触发
socket.on("ping", () => {
console.log("一个ping发送到服务器-ping")
});
// 当服务器收到pong时触发
socket.on("pong", (data) => {
// data: 延迟多少ms
console.log("服务器收到pong-pong", data);
});
客户端向服务端socket发送信息:
socket.emit("eventName", msg, handler)//handler回调可以接受到服务端返回的结果
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。