1、WebSocket 是一种网络协议,用于在客户端和服务器之间进行双向通信。它允许在一个单独的 TCP 连接上进行全双工通信,因此比传统的 HTTP 请求-响应模型更高效。
1.1、WebSocket 协议通过在 HTTP 握手期间建立握手协议升级机制来启动连接。一旦建立连接,客户端和服务器可以在任何时候向对方发送数据。与传统的 HTTP 连接不同,WebSocket 连接保持打开状态,直到其中一方关闭连接或网络错误导致连接中断。
1.2、WebSocket 可以用于实时 Web 应用程序、多人在线游戏、聊天应用程序等场景,可以提供更低的延迟和更快的响应速度。WebSocket 协议也得到了广泛支持,现代浏览器和服务器都已经内置了 WebSocket 支持,许多编程语言和框架也提供了 WebSocket 实现。
2、先判断浏览器是否支持:if(window.WebSocket)
if(window.WebSocket){
console.log("支持")
}else{
console.log("不支持")
}
3、WebSocket是一种通信协议,用于在客户端和服务器之间进行双向通信。它允许Web浏览器和服务器之间实时交换数据,可以替代传统的HTTP轮询技术。
3.1、以下是WebSocket的基本使用步骤:
客户端通过JavaScript代码创建WebSocket对象,指定WebSocket服务器的地址:
var socket = new WebSocket("ws://example.com/socket");
当连接成功建立后,WebSocket对象的onopen回调函数会被调用。在这个回调函数中,您可以执行一些初始化操作或发送第一条消息:
socket.onopen = function(event) {
// 在此处执行初始化操作或发送第一条消息
};
当WebSocket接收到来自服务器的数据时,WebSocket对象的onmessage回调函数会被调用,并将接收到的数据作为参数传递给该函数:
socket.onmessage = function(event) {
console.log("收到消息:" + event.data);
};
客户端可以通过WebSocket对象的send()方法向服务器发送消息:
socket.send("Hello, server!");
当客户端不再需要WebSocket连接时,应该调用WebSocket对象的close()方法关闭连接:
socket.close();
服务器也可以通过WebSocket对象发送消息到客户端。当服务器发送消息时,客户端的onmessage回调函数会被调用,客户端可以在该回调函数中处理接收到的消息。
以上是WebSocket最基本的使用方法。除此之外,WebSocket还支持多种高级特性,例如二进制数据传输、ping/pong帧、断开重连等。
3.2、前后端链接的基础使用:
WebSocket 是一种在 Web 应用程序中实现双向通信的协议。在 Node.js 中,可以使用 ws 模块来创建 WebSocket 服务器。
下面是一个简单的示例:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8281 });
wss.on('connection', (ws) => {
console.log('Client connected');
ws.on('message', (message) => {
console.log(`前端数据: ${message}`);
ws.send(`发送给前端: ${message}`);
});
ws.on('close', () => {
console.log('断开链接');
});
});
这个例子创建了一个 WebSocket 服务器,监听端口 8080。当客户端连接时,会触发 connection 事件,并打印出 "Client connected"。然后,当收到客户端发送的消息时,会触发 message 事件,并打印出接收到的消息,同时将消息原样返回给客户端。最后,当客户端断开连接时,会触发 close 事件,并打印出 "Client disconnected"。
在客户端,可以使用浏览器内置的 WebSocket API 或者第三方库(如 Socket.IO)来与服务器建立连接并进行通信。例如:
const socket = new WebSocket('ws://localhost:8281');
socket.addEventListener('open', () => {
console.log('建立链接');
});
socket.addEventListener('message', (event) => {
console.log(`后端发送的数据: ${event.data}`);
});
socket.addEventListener('close', () => {
console.log('关闭链接');
});
socket.send('发送数据给后端');
这个例子创建了一个 WebSocket 连接,连接到本地的 WebSocket 服务器。当连接建立时,会触发 open 事件,并打印出 "Connected to server"。然后,当收到服务器发送的消息时,会触发 message 事件,并打印出接收到的消息。最后,当连接断开时,会触发 close 事件,并打印出 "Disconnected from server"。在连接建立后,客户端可以使用 send 方法向服务器发送消息。
4、WebSocket的前端配置:
if (window.WebSocket) {
const ws = new WebSocket('ws://localhost:8888')
console.log(ws)
ws.onopen = () => {
console.log('前端已经连接后端成功!')
}
ws.onerror = () => {
console.log('前端和后端连接错误!')
}
ws.onclose = () => {
console.log('后端关闭连接!')
}
ws.onmessage = data => {
console.log('后端给前端推送信息了..,', data)
}
} else {
alert('您的浏览器不支持WebSocket,请升级您的浏览器')
}
5、WebSocket的后端配置:
5.1、下载模块:cnpm i ws --save
5.2、基本操作:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8888});
wss.on('connection', (ws) => {
console.log('Client connected');
ws.on('message', (message) => {
console.log(`前端数据: ${message}`);
ws.send(`发送给前端: ${message}`);
});
ws.on('close', () => {
console.log('断开链接');
});
});
6、 wss.clients.forEach():多人链接同一个端口,将每个人发送的消息都发送前端,实现多人聊天
6.1、"wss.clients.forEach()"将会对WebSocket服务器的每个客户端执行指定的操作。例如,可以使用它来向所有连接的客户端广播消息。
// 引入模块 npm i ws --save 1.nodejs-websocket
const WebSocket = require('ws');
// 创建一个WebSocketServer的实例,监听端口8080
const wss = new WebSocket.Server({ port: 8888 });
// 监听连接
wss.on('connection', (ws) => {
// console.log(wss.clients);
// ws.on('message', function incoming(message) {
// console.log('received: %s', message);
// ws.send('Hi Client');
// });//当收到消息时,在控制台打印出来,并回复一条信息
ws.on('message', (mes) => {
console.log(JSON.parse(mes));
//多人链接同一个端口,将每个人发送的消息都发送前端,实现多人聊天
wss.clients.forEach((client) => {
client.send(JSON.parse(mes));
});
})
// ws.send('Hello Client!')
});
7、二次封装WebSocket:
7.1、后端:在utils工具包创建WebSocket_server.js文件:
// 导入fs模块
const fs = require('fs');
// 导入path模块
const path = require('path');
// 引入模块 npm i ws --save 1.nodejs-websocket 2.websocket.io
const WebSocket = require('ws');
// 创建一个WebSocketServer的实例,监听端口8080
const wss = new WebSocket.Server({ port: 8888 });
// 封装listen暴露出去
const listen = () => {
// 监听连接
wss.on('connection', (ws) => {
console.log('cake-admin连接进来啦...');
// ws.on('message', function incoming(message) {
// console.log('received: %s', message);
// ws.send('Hi Client');
// });//当收到消息时,在控制台打印出来,并回复一条信息
ws.on('message', (mes) => {
console.log(JSON.parse(mes));
// 多人发送响应,比如多人聊天室
// wss.clients.forEach((client) => {
// client.send(JSON.parse(mes));
// });
// 单人发送响应,比如管理后台
// ws.send('Hello Client!')
let result = JSON.parse(mes);
// console.log(typeof result);
if (result.echarts === 'option1') {
fs.readFile(path.resolve(__dirname, '../data/option1.json'), 'utf-8', (err, data) => {
if (err) throw err;
// 2.第二种方式: 在获取数据的时候,通过toString()转换成字符串
// console.log(data.toString());
// console.log(data); // {'one':[],'two':[],'three':[],'four':[]}
data = JSON.parse(data);
// 封装随机数函数
function rand(max, min) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
// 向数据库实时查询数据是否有更新
setInterval(() => {
for (let i = 0; i < 12; i++) {
data.one[i] = rand(20, 1)
data.two[i] = rand(20, 1)
data.three[i] = rand(20, 1)
data.four[i] = rand(20, 1)
}
// console.log(data);
// res.send(data);
ws.send(JSON.stringify(data))
}, 2000)
})
}
})
// ws.send('Hello Client!')
});
}
module.exports = listen;
7.2、前端:在utils工具包创建WebSocket.js文件:函数式封装:
var websock = null;
let rec; //断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码
let isConnect = false; //连接标识 避免重复连接
let checkMsg = "heartbeat"; //心跳发送/返回的信息 服务器和客户端收到的信息内容如果如下 就识别为心跳信息 不要做业务处理
// 注册全局的回调函数
let globalCallback = function () { };
let createWebSocket = () => {
try {
// websocket 初始化
initWebSocket(); //初始化websocket连接
} catch (e) {
console.log("尝试创建连接失败");
// websocket 重新连接
reConnect(); //如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接
}
};
//定义重连函数
let reConnect = () => {
console.log("尝试重新连接");
if (isConnect) return; //如果已经连上就不在重连了
rec && clearTimeout(rec);
rec = setTimeout(function () { // 延迟5秒重连 避免过多次过频繁请求重连
createWebSocket();
}, 5000);
};
//设置关闭连接
let closeWebSocket = () => {
websock.close();
};
//心跳设置
var heartCheck = {
timeout: 20000, //每段时间发送一次心跳包 这里设置为20s
timeoutObj: null, //延时发送消息对象(启动心跳新建这个对象,收到消息后重置对象)
start: function () {
this.timeoutObj = setTimeout(function () {
if (isConnect) websock.send(checkMsg);
}, this.timeout);
},
reset: function () {
clearTimeout(this.timeoutObj);
this.start();
}
};
// 初始化websocket
function initWebSocket() {
// ws地址 -->这里是你的请求路径
var ws = "ws://localhost:8888"
// 创建websocket连接
websock = new WebSocket(ws)
// 监听后端的响应
websock.onmessage = function (e) {
websocketonmessage(e)
}
// 监听websocket的关闭
websock.onclose = function (e) {
websocketclose(e)
}
// 监听websocket的连接
websock.onopen = function () {
websocketOpen()
// heartCheck.start();
}
// 连接发生错误的回调方法
websock.onerror = function () {
console.log('WebSocket连接发生错误')
isConnect = false; //连接断开修改标识
reConnect(); //连接错误 需要重连
}
}
// 实际调用的方法
function sendSock(agentData, callback) {
globalCallback = callback
// console.log(globalCallback)
if (websock.readyState === websock.OPEN) {
// 若是ws开启状态
websocketsend(agentData)
} else if (websock.readyState === websock.CONNECTING) {
// 若是 正在开启状态,则等待1s后重新调用
setTimeout(function () {
sendSock(agentData, callback)
}, 1000)
} else {
// 若未开启 ,则等待1s后重新调用
setTimeout(function () {
sendSock(agentData, callback)
}, 1000)
}
}
function getSock(callback) {
globalCallback = callback
}
// 数据接收
function websocketonmessage(e) {
// console.log(e.data)
let O_o = JSON.parse(decodeUnicode(e.data))
console.log(O_o);
if (!O_o) {
heartCheck.reset();
} else {
if (O_o.msg == "open success") {
sessionStorage.setItem("wid", O_o.wid);
} else {
// console.log(O_o);
globalCallback(O_o);
}
}
// globalCallback(JSON.parse(e.data))
function decodeUnicode(str) {
str = str.replace(/\\/g, "%");
//转换中文
str = unescape(str);
//将其他受影响的转换回原来
str = str.replace(/%/g, "\\");
//对网址的链接进行处理
str = str.replace(/\\/g, "");
return str;
}
}
// 数据发送
function websocketsend(agentData) {
console.log(JSON.stringify(agentData))
websock.send(JSON.stringify(agentData))
}
// 关闭
function websocketclose(e) {
console.log(e)
isConnect = false; //断开后修改标识
console.log('connection closed (' + e.code + ')')
}
// 创建 websocket 连接
function websocketOpen(e) {
console.log('连接成功')
}
// initWebSocket()
// 将方法暴露出去
export {
initWebSocket,
sendSock,
getSock,
createWebSocket,
closeWebSocket
};
7.2、前端:在utils工具包创建WebSocket.js文件:类式封装:
// 单例模式的类封装
export default class SocketService {
static instance = null;
static get Instance() {
if (!this.instance) {
this.instance = new SocketService();
}
return this.instance;
}
// 和服务端连接的socket对象
ws = null;
// 存储回调函数
callBackMapping = {};
// 标识是否连接成功
connected = false;
// 记录重试的次数
sendRetryCount = 0;
// 重新连接尝试的次数
connectRetryCount = 0;
// 定义连接服务器的方法
connect() {
// 连接服务器
if (!window.WebSocket) {
return console.log('您的浏览器不支持WebSocket');
}
let url = 'ws://localhost:8888';
this.ws = new WebSocket(url);
// 连接成功的事件
this.ws.onopen = () => {
console.log('连接服务端成功了');
this.connected = true;
// 重置重新连接的次数
this.connectRetryCount = 0;
};
// 1.连接服务端失败
// 2.当连接成功之后, 服务器关闭的情况
this.ws.onclose = () => {
console.log('连接服务端失败');
this.connected = false;
this.connectRetryCount++;
setTimeout(() => {
this.connect();
}, 500 * this.connectRetryCount);
};
// 得到服务端发送过来的数据
this.ws.onmessage = msg => {
console.log(msg.data, '从服务端获取到了数据');
};
}
// 回调函数的注册
registerCallBack(socketType, callBack) {
this.callBackMapping[socketType] = callBack;
}
// 取消某一个回调函数
unRegisterCallBack(socketType) {
this.callBackMapping[socketType] = null;
}
// 发送数据的方法
send(data) {
// 判断此时此刻有没有连接成功
if (this.connected) {
this.sendRetryCount = 0;
try {
this.ws.send(JSON.stringify(data));
} catch (e) {
this.ws.send(data);
}
} else {
this.sendRetryCount++;
setTimeout(() => {
this.send(data);
}, this.sendRetryCount * 500);
}
}
}
参考链接
发表评论