目录
WebSocket.close([code[, reason]])
一、Websocket是什么
当一个Web应用程序需要实现实时双向通信时,传统的 HTTP 协议并不是最佳选择,因为HTTP是一个请求/响应协议,它的工作方式是客户端发送一个请求给服务器,服务器然后响应该请求,并发送一个响应给客户端。这种模式通常是单向的,客户端只能发起请求,而服务器只能响应请求。这意味着,客户端无法在不发出新请求的情况下接收来自服务器的新数据。
WebSocket 协议就是为了解决这个问题而产生的,它可以在客户端和服务器之间建立持久的连接,以便实现双向通信。在建立连接之后,客户端和服务器可以随时发送消息,而不需要通过HTTP请求/响应的方式进行通信。此外,WebSocket还支持二进制数据的传输,这使得它更加灵活,可以用于许多不同的应用程序场景。
WebSocket协议的工作方式如下:
- 客户端向服务器发起一个WebSocket握手请求。这个请求与HTTP请求非常相似,但包含了一些附加的头部信息,以表示这是一个WebSocket请求。
- 服务器对该请求进行响应,包含一个状态码和一些头部信息。这个响应是HTTP响应,但同样包含了一些附加的头部信息,以表示这是一个WebSocket响应。
- 客户端和服务器之间的连接现在已经建立,并且可以进行双向通信了。客户端和服务器都可以随时发送消息,这些消息会被封装为WebSocket帧并通过WebSocket连接进行传输。
需要注意的是,WebSocket协议与传统的HTTP协议不同,因为它不是基于请求/响应模式的。这意味着,一旦连接建立,客户端和服务器就可以随时发送消息,而不需要等待对方先发出请求。此外,WebSocket协议还支持心跳包机制,可以检测连接是否还处于活动状态。
总之,WebSocket协议提供了一种高效、可靠、灵活的方式来实现Web应用程序之间的实时双向通信。它是一个强大的工具,可以用于许多不同的应用程序场景,包括在线游戏、实时聊天、数据传输和多人协作等等。
二、Websocket的基本使用
使用介绍
前端使用WebSocket通常需要使用浏览器提供的WebSocket API,该API可以通过JavaScript代码与WebSocket服务器建立连接,并在连接建立后进行数据传输。
第一步
创建一个WebSocket对象。可以使用以下代码创建一个WebSocket对象:
const socket = new WebSocket('ws://localhost:8080');
在创建WebSocket对象时,需要传递WebSocket服务器的地址和端口号作为参数。WebSocket服务器地址可以使用ws://
或wss://
前缀表示,ws://
表示使用普通的HTTP协议进行通信,wss://
表示使用加密的HTTP协议进行通信。
第二步
监听WebSocket事件。WebSocket API提供了几种事件类型,可以通过这些事件来处理WebSocket的连接状态和数据传输。下面是常用的事件类型:
open
:WebSocket连接成功时触发。message
:接收到WebSocket服务器发送的消息时触发。error
:WebSocket连接出错时触发。close
:WebSocket连接关闭时触发。
可以使用下面的代码监听WebSocket事件:
socket.addEventListener('open', (event) => {
console.log('WebSocket连接已打开');
});
socket.addEventListener('message', (event) => {
console.log('接收到消息:', event.data);
});
socket.addEventListener('error', (event) => {
console.log('WebSocket连接出错:', event);
});
socket.addEventListener('close', (event) => {
console.log('WebSocket连接已关闭');
});
第三步
发送数据。可以使用WebSocket.send()
方法向WebSocket服务器发送数据。该方法接受一个字符串或一个二进制数据对象作为参数。下面是一个例子:
这里需要注意的是如果传输的数据为对象格式,应转换为JOSN格式进行传输。
socket.send('Hello, WebSocket!');
第四步
关闭连接。可以使用WebSocket.close()
方法关闭WebSocket连接。
socket.close();
常用API介绍
WebSocket(url[, protocols])
创建WebSocket对象。其中,url参数是WebSocket服务器的地址,protocols参数是一个可选的字符串或字符串数组,表示WebSocket协议的子协议列表。(见使用介绍第一步)
WebSocket.readyState
WebSocket对象的只读属性,表示当前WebSocket的连接状态,它的值为下面四个之一:
- 0 - 表示WebSocket连接尚未建立。
- 1 - 表示WebSocket连接已建立,可以进行通信。
- 2 - 表示WebSocket连接正在关闭。
- 3 - 表示WebSocket连接已经关闭或者连接不能打开。
console.log(this.webSocket.readyState)
WebSocket.send(data)
向WebSocket服务器发送数据。其中,data参数可以是一个字符串、一个二进制数据对象或者一个Blob对象。(见使用介绍第三步)
WebSocket.close([code[, reason]])
关闭WebSocket连接。其中,code参数表示关闭代码,reason参数表示关闭原因。(见使用介绍第四步)
WebSocket.bufferedAmount
WebSocket的bufferedAmount
属性表示已经被send()方法发送但还没有被发送到网络层的数据量。在发送数据的过程中,如果发送的数据量大于WebSocket的缓冲区大小,那么这些数据就会被暂时保存在WebSocket的缓冲区中,直到网络层可以接受这些数据时再发送出去。
const socket = new WebSocket('ws://localhost:8080');
console.log('初始bufferedAmount:', socket.bufferedAmount);
socket.send('Hello, WebSocket!');
console.log('发送后bufferedAmount:', socket.bufferedAmount);
WebSocket.extensions
WebSocket的extensions
属性是一个只读属性,它表示WebSocket服务器支持的扩展列表。
const socket = new WebSocket('ws://localhost:8080');
console.log('WebSocket服务器支持的扩展:', socket.extensions);
WebSocket.binaryType
WebSocket的binaryType
属性表示在收到二进制数据时使用的编码方式,默认值是"blob"。可以将其设置为"arraybuffer"来使用ArrayBuffer对象来处理二进制数据。
const socket = new WebSocket('ws://localhost:8080');
socket.binaryType = 'arraybuffer';
socket.addEventListener('message', (event) => {
const arrayBuffer = event.data;
// 处理二进制数据
});
三、Websocket的封装
vue代码
import Vue from 'vue'
import { Message } from 'element-ui'
let v = new Vue()
v.$message = Message;
var webSocket = null;
var isConnect = false; //连接状态
var globalCallback = function(e){ console.log(e) };//定义外部接收数据的回调函数
var reConnectNum = 0;//重连次数
var websocketUrl = process.env.VUE_APP_API_WEBSOCKET_URL;
//心跳设置
var heartCheck = {
heartbeatData:{
DevID:{
value:Vue.ls.get('devid')
},
DevHeart:{
value:"1"
}
},//心跳包
timeout: 60 * 1000, //每段时间发送一次心跳包 这里设置为60s
heartbeat: null, //延时发送消息对象(启动心跳新建这个对象,收到消息后重置对象)
start: function () {
this.heartbeat = setInterval(()=>{
if (isConnect){
webSocketSend(this.heartbeatData);
}else{
this.clear();
}
}, this.timeout);
},
reset: function () {
clearInterval(this.heartbeat);
this.start();
},
clear:function(){
clearInterval(this.heartbeat);
}
}
//初始化websocket
function initWebSocket(callback) {
//此callback为在其他地方调用时定义的接收socket数据的函数
if(callback){
if(typeof callback == 'function'){
globalCallback = callback
}else{
throw new Error("callback is not a function")
}
}
if ("WebSocket" in window) {
webSocket = new WebSocket(websocketUrl);//创建socket对象
} else {
Message({
message: '该浏览器不支持websocket!',
type: 'warning'
});
return
}
//打开
webSocket.onopen = function() {
webSocketOpen();
};
//收信
webSocket.onmessage = function(e) {
webSocketOnMessage(e);
};
//关闭
webSocket.onclose = function(e) {
webSocketOnClose(e);
};
//连接发生错误的回调方法
webSocket.onerror = function(e) {
webSocketonError(e);
};
}
//连接socket建立时触发
function webSocketOpen() {
console.log("WebSocket连接成功");
//首次握手
webSocketSend(heartCheck.heartbeatData);
isConnect = true;
heartCheck.start();
reConnectNum = 0;
}
//客户端接收服务端数据时触发,e为接受的数据对象
function webSocketOnMessage(e) {
console.log("websocket信息:");
console.log(e.data)
const data = JSON.parse(e.data);//根据自己的需要对接收到的数据进行格式化
globalCallback(data);//将data传给在外定义的接收数据的函数,至关重要。
}
//socket关闭时触发
function webSocketOnClose(e){
heartCheck.clear();
isConnect = false; //断开后修改标识
console.log(e)
console.log('webSocket已经关闭 (code:' + e.code + ')')
//被动断开,重新连接
if(e.code == 1006){
if(reConnectNum < 3){
initWebSocket();
++reConnectNum;
}else{
v.$message({
message: 'websocket连接不上,请刷新页面或联系开发人员!',
type: 'warning'
});
}
}
}
//连接发生错误的回调方法
function webSocketonError(e){
heartCheck.clear();
isConnect = false; //断开后修改标识
console.log("WebSocket连接发生错误:");
console.log(e);
}
//发送数据
function webSocketSend(data) {
webSocket.send(JSON.stringify(data));//在这里根据自己的需要转换数据格式
}
//在其他需要socket地方主动关闭socket
function closeWebSocket(e) {
webSocket.close();
heartCheck.clear();
isConnect = false;
reConnectNum = 0;
}
//在其他需要socket地方接受数据
function getSock(callback) {
globalCallback = callback
}
//在其他需要socket地方调用的函数,用来发送数据及接受数据
function sendSock(agentData) {
//下面的判断主要是考虑到socket连接可能中断或者其他的因素,可以重新发送此条消息。
switch (webSocket.readyState) {
//CONNECTING:值为0,表示正在连接。
case webSocket.CONNECTING:
setTimeout(function() {
sendSock(agentData, callback);
}, 1000);
break;
//OPEN:值为1,表示连接成功,可以通信了。
case webSocket.OPEN:
webSocketSend(agentData);
break;
//CLOSING:值为2,表示连接正在关闭。
case webSocket.CLOSING:
setTimeout(function() {
sendSock(agentData, callback);
}, 1000);
break;
//CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
case webSocket.CLOSED:
// do something
break;
default:
// this never happens
break;
}
}
export default {
initWebSocket,
closeWebSocket,
sendSock,
getSock
};
react代码
import React, { Component } from 'react';
class WebSocketHelper extends Component {
constructor(props) {
super(props);
this.state = {
websocket: null,
heartBeatIntervalId: null,
};
}
componentDidMount() {
this.connectWebSocket();
}
componentWillUnmount() {
this.closeWebSocket();
}
connectWebSocket = () => {
const websocket = new WebSocket(this.props.url);
websocket.onopen = () => {
console.log('WebSocket connection opened.');
this.props.onOpen && this.props.onOpen();
if (this.props.heartBeatInterval) {
const heartBeatIntervalId = setInterval(() => {
console.log('Sending WebSocket heartbeat.');
this.sendMessage(this.props.heartBeatMessage);
}, this.props.heartBeatInterval);
this.setState({ heartBeatIntervalId });
}
};
websocket.onclose = () => {
console.log('WebSocket connection closed.');
this.props.onClose && this.props.onClose();
if (this.state.heartBeatIntervalId) {
clearInterval(this.state.heartBeatIntervalId);
this.setState({ heartBeatIntervalId: null });
}
setTimeout(() => {
console.log('Attempting to reconnect WebSocket.');
this.connectWebSocket();
}, this.props.reconnectInterval || 5000);
};
websocket.onerror = (error) => {
console.error('WebSocket error:', error);
this.props.onError && this.props.onError(error);
};
websocket.onmessage = (event) => {
console.log('WebSocket message received:', event.data);
this.props.onMessage && this.props.onMessage(event.data);
};
this.setState({ websocket });
}
closeWebSocket = () => {
if (this.state.websocket) {
this.state.websocket.close();
console.log('WebSocket connection closed.');
if (this.state.heartBeatIntervalId) {
clearInterval(this.state.heartBeatIntervalId);
this.setState({ heartBeatIntervalId: null });
}
}
}
sendMessage = (message) => {
if (this.state.websocket) {
console.log('Sending WebSocket message:', message);
this.state.websocket.send(message);
}
}
render() {
return this.props.render({
sendMessage: this.sendMessage,
closeWebSocket: this.closeWebSocket,
});
}
}
export default WebSocketHelper;
使用
import React from 'react';
import WebSocketHelper from './WebSocketHelper';
function App() {
const handleOpen = () => {
console.log('WebSocket connection opened.');
};
const handleClose = () => {
console.log('WebSocket connection closed.');
};
const handleError = (error) => {
console.error('WebSocket error:', error);
};
const handleMessage = (message) => {
console.log('WebSocket message received:', message);
};
const handleRender = ({ sendMessage, closeWebSocket }) => {
// 这里可以使用 sendMessage 和 closeWebSocket 方法
return (
<div>
<button onClick={() => sendMessage('Hello WebSocket!')}>Send Message</button>
<button onClick={() => closeWebSocket()}>Close WebSocket</button>
</div>
);
};
return (
<WebSocketHelper
url="wss://example.com"
onOpen={handleOpen}
onClose={handleClose}
onError={handleError}
onMessage={handleMessage}
render={handleRender}
/>
);
}
export default App;
更多详细信息详见官网:https://www.websocket.org/https://www.websocket.org/