目录
websocket在线测试工具:
WebSocket在线测试工具 (qianbo.com.cn)https://www.qianbo.com.cn/Tool/WebSocket/WebSocket在线测试工具 (wstool.js.org)http://wstool.js.org/WebSocket在线测试 - 您的超级在线工具 - https://www.tmdtool.comhttp://websocket.tmdtool.com/
WebSocket是一种在Web应用程序中实现双向通信的通信协议,它允许客户端和服务器之间建立持久的、低延迟的连接,以实现实时数据传输。相比传统的HTTP请求,WebSocket更适合需要实时性和交互性的应用程序。
WebSocket解决了传统HTTP请求的一些限制,例如:
- 实时性: 传统HTTP请求需要客户端定期轮询服务器以获取新数据,而WebSocket允许服务器主动推送数据给客户端,实现实时更新。
- 双向通信: WebSocket支持双向通信,客户端和服务器都可以发送消息,而不是仅限于客户端向服务器发送请求。
- 低延迟: WebSocket连接保持开放,减少了连接和断开的开销,从而实现更低的通信延迟。
- 跨平台:WebSocket协议是一种标准化的协议,被广泛支持和应用于不同的平台和编程语言中
关于WebSocket通信的简单介绍:
- 握手阶段:在建立WebSocket连接之前,客户端需要发送一个HTTP请求到服务器,请求升级为WebSocket协议。这个过程称为握手(Handshake)。如果服务器支持WebSocket协议,它将返回带有特定标头的HTTP响应,表示握手成功。
- 建立连接:客户端收到服务器的握手响应后,会重新建立连接。此时,连接将从HTTP协议切换到WebSocket协议,并保持打开状态。这样就建立了可持续的双向通信通道。
- 数据传输:一旦WebSocket连接建立,客户端和服务器可以开始互相发送消息。客户端和服务器都可以通过发送文本或二进制数据来通信。消息可以是简单的字符串,也可以是复杂的数据结构,如JSON对象等。
- 断开连接:当需要关闭WebSocket连接时,客户端或服务器可以主动发送一个关闭帧来断开连接。收到关闭帧的一方会结束连接并发送回应帧,完成连接的关闭。
创建websocket服务端
新建文件夹a,并在a目录下生成package.json。执行以下命令即可:
npm init -y
安装依赖包:
npm i koa ws
在package.json的同级目录下新建index.js文件:
const Koa = require('koa');
const WebSocket = require('ws');
const http = require('http');
const app = new Koa();
const server = http.createServer(app.callback());
const wss = new WebSocket.Server({ server });
const port = 3039;
wss.on('connection', (ws) => {
console.log('WebSocket 连接已建立!');
ws.on('message', (message) => {
console.log(`收到消息:${message}`);
// 向客户端发送消息
setInterval(() => {
ws.send(JSON.stringify({
data: {
position: [104, 30, 100],
type: 1
}
}));
}, 1000)
});
});
server.listen(port, () => {
console.log(`ws地址:ws://localhost:${port}`);
});
执行命令启动服务端:
node index.js
创建websocket客户端
新建html文件,内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test</title>
<style>
* {
margin: 0;
padding: 0
}
</style>
</head>
<body>
</body>
<script>
const ws = new WebSocket('ws://localhost:3039');
ws.onopen = () => {
console.log('WebSocket 连接已建立!');
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ username: '张三', age: 33 }));
} else {
console.error('Websocket未连接');
}
};
ws.onmessage = (event) => {
console.log(`收到消息:${event.data}`);
};
</script>
</html>
双击打开html文件,按F12查看控制台打印
可见连接成功!
在websocket在线工具中查看效果:WebSocket在线测试 - 您的超级在线工具 - https://www.tmdtool.comhttp://websocket.tmdtool.com/
其他示例
示例1:
<template>
<div></div>
</template>
<script>
export default {
data() {
return {
websocket: null, // WebSocket对象
reconnectInterval: 3000, // 重连间隔时间(毫秒)
heartbeatInterval: null, // 心跳定时器
};
},
created() {
this.setupWebSocket(); // 创建WebSocket连接
},
methods: {
setupWebSocket() {
this.websocket = new WebSocket("ws链接地址"); // 创建WebSocket连接
this.websocket.onopen = this.onWebSocketOpen; // WebSocket连接打开时的处理函数
this.websocket.onmessage = this.onWebSocketMessage; // 收到WebSocket消息时的处理函数
this.websocket.onclose = this.onWebSocketClose; // WebSocket连接关闭时的处理函数
},
closeWebSocket() {
if (this.websocket) {
this.websocket.close(); // 关闭WebSocket连接
}
},
/**
* WebSocket连接打开后,启动心跳检测
*/
onWebSocketOpen() {
console.log("WebSocket connection is open");
this.startHeartbeat();
// 发送初始化消息
const initMessage = {
type: "sub",
topic: "/aa/bb/cc/d",
parameter: {},
id: "bb",
};
this.sendMessage(JSON.stringify(initMessage));
},
// 处理从服务器接收的消息
onWebSocketMessage(event) {
if (event.data) {
const message = JSON.parse(event.data);
// 根据业务来处理数据
}
},
onWebSocketClose() {
console.log("WebSocket connection is closed");
this.stopHeartbeat(); // WebSocket连接关闭时,停止心跳检测
setTimeout(this.setupWebSocket, this.reconnectInterval); // 在一定时间后重连WebSocket
},
sendMessage(message) {
if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
this.websocket.send(message); // 发送消息到WebSocket服务器
}
},
startHeartbeat() {
this.heartbeatInterval = setInterval(() => {
if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
this.websocket.send("ping"); // 发送心跳消息
}
}, 10000); // 每10秒发送一次心跳
},
stopHeartbeat() {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval); // 停止心跳检测定时器
}
},
},
beforeDestroy() {
this.closeWebSocket(); // 在组件销毁前关闭WebSocket连接
},
};
</script>
<style lang="scss" scoped></style>
示例2:
import { onUnmounted, ref } from 'vue'
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
interface QueryType {
url: string //url
options?: OptionsType //配置
params?: object //url参数
onmessage?: Function //回调函数
}
interface OptionsType {
maxReconnect?: number //最大重连次数, -1 标识无限重连
interval?: number //心跳间隔
timeout?: number // 响应超时时间
pingMessage?: string // 心跳请求信息
}
const defaultOptions = {
maxReconnect: 6,
interval: 30 * 1000,
timeout: 10 * 1000,
pingMessage: 'ping'
}
/**
* websocket封装
* @param {object} param0
* @returns serverMessage, sendMessage, destroySocket
*/
export default function useWebSocket({ url, options = {}, params, onmessage }: QueryType) {
const OPTION = { ...defaultOptions, ...options }
let socket: WebSocket | null = null //websocket实例
let pingTimeoutObj: NodeJS.Timeout | null = null //延时发送心跳的定时器
let pongTimeoutObj: NodeJS.Timeout | null = null //接收心跳响应的定时器
let reconnectCount: number = 0 // 重连尝试次数
let lockReconnect: Boolean = false // 重连锁,避免多次重连
const token = useSystemStore().getToken
// 初始化连接socket
function initWebSocket() {
const VITE_APP_SOCKET_API = import.meta.env.VITE_APP_SOCKET_API
const _params = objectToEncodeQuery(params)
const wsUri = `${VITE_APP_SOCKET_API}${url}?token=${token}` + _params
socket = new WebSocket(wsUri)
// 连接成功
socket.onopen = onOpen
// 连接错误
socket.onerror = onError
// 接收信息
socket.onmessage = onMessage
// 连接关闭
socket.onclose = onClose
}
/**
* 连接成功事件
*/
function onOpen() {
// 开启心跳
startHeartbeat()
reconnectCount = 0
}
/**
* 连接失败事件
* @param e
*/
function onError(e) {
console.error(`WebSocket connection error:${e.code} ${e.reason} ${e.wasClean}`)
reconnect()
}
/**
* 连接关闭事件
* @param e
*/
function onClose() {
reconnect()
}
/**
* 重新连接
*/
function reconnect() {
if (!token) {
return
}
if (lockReconnect || (OPTION.maxReconnect !== -1 && reconnectCount > OPTION.maxReconnect)) {
return
}
lockReconnect = true
setTimeout(() => {
reconnectCount++
// 建立新连接
initWebSocket()
lockReconnect = false
}, 5000)
}
/**
* 清空定时器
*/
function clearTimeoutObj() {
pingTimeoutObj && clearTimeout(pingTimeoutObj)
pongTimeoutObj && clearTimeout(pongTimeoutObj)
}
/**
* 开启心跳
*/
function startHeartbeat() {
console.log('startHeartbeat')
// 清空定时器
pingTimeoutObj && clearTimeout(pingTimeoutObj)
// 延时发送下一次心跳
pingTimeoutObj = setTimeout(() => {
sendMessage(OPTION.pingMessage)
}, OPTION.interval)
}
const serverMessage = ref()
/**
* 接收服务器推送的信息
* @param msgEvent
*/
function onMessage(msgEvent) {
console.log('msgEvent')
// 收到服务器信息,心跳重置并发送
startHeartbeat()
const text = msgEvent.data
if (text === 'pong') {
return
}
const data = JSON.parse(msgEvent.data)
serverMessage.value = data.data
onmessage && onmessage(data.data)
}
function sendMessage(message: string) {
// 如果连接正常
if (socket && socket.readyState === 1) {
// 这里发送一个心跳,后端收到后,返回一个心跳消息,
socket.send(message)
// 心跳发送后,如果服务器超时未响应则断开,如果响应了会被重置心跳定时器
pongTimeoutObj && clearTimeout(pongTimeoutObj)
pongTimeoutObj = setTimeout(() => {
socket && socket.close()
}, OPTION.timeout)
} else {
// 否则重连
reconnect()
}
}
/**
* 销毁socket
*/
function destroySocket() {
if (socket) {
lockReconnect = true
socket.close()
clearTimeoutObj()
}
}
// 断开连接
onUnmounted(() => {
destroySocket()
})
/**
* 对象转url参数
*/
function objectToEncodeQuery(query: object | undefined): string {
if (!query) return ''
const params = Object.keys(query)
.filter(key => query[key])
.map(key => {
return encodeURIComponent(key) + '=' + encodeURIComponent(query[key])
})
.join('&')
return params
}
initWebSocket()
return { serverMessage, sendMessage, destroySocket }
}
示例3:
// src/utils/websocket.ts
import { ref, onUnmounted } from 'vue';
interface WebSocketOptions {
url: string;
protocols?: string | string[];
reconnectTimeout?: number;
}
class WebSocketService {
private ws: WebSocket | null = null;
private callbacks: { [key: string]: Function[] } = {};
private reconnectTimeoutMs: number = 5000; // 默认5秒重连间隔
constructor(private options: WebSocketOptions) {}
public open(): void {
this.ws = new WebSocket(this.options.url, this.options.protocols)
this.ws.addEventListener('open', this.handleOpen);
this.ws.addEventListener('message', this.handleMessage);
this.ws.addEventListener('error', this.handleError);
this.ws.addEventListener('close', this.handleClose);
}
public close(isActiveClose = false): void {
if (this.ws) {
this.ws.close();
if (!isActiveClose) {
setTimeout(() => this.reconnect(), this.reconnectTimeoutMs);
}
}
}
public reconnect(): void {
this.open();
}
public on(event: 'message', callback: (data: any) => void): void;
public on(event: 'open' | 'error' | 'close', callback: () => void): void;
public on(event: string, callback: (...args: any[]) => void): void {
if (!this.callbacks[event]) {
this.callbacks[event] = [];
}
this.callbacks[event].push(callback);
}
private handleOpen = (): void => {
console.log('WebSocket连接已建立');
if (this.callbacks.open) {
this.callbacks.open.forEach((cb) => cb());
}
};
private handleMessage = (event: MessageEvent): void => {
const data = JSON.parse(event.data);
console.log('WebSocket接收到消息:', data);
if (this.callbacks.message) {
this.callbacks.message.forEach((cb) => cb(data));
}
};
private handleError = (error: Event): void => {
console.error('WebSocket错误:', error);
if (this.callbacks.error) {
this.callbacks.error.forEach((cb) => cb(error));
}
};
private handleClose = (): void => {
console.log('WebSocket连接已关闭');
if (this.callbacks.close) {
this.callbacks.close.forEach((cb) => cb());
if (!this.options.reconnectTimeout) {
this.reconnect();
}
}
};
public send(data: any): void {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
} else {
console.warn('尝试发送消息时WebSocket未连接');
}
}
}
export default function useWebSocket(options: WebSocketOptions) {
const wsService = new WebSocketService(options);
onUnmounted(() => {
wsService.close(true);
});
return {
open: wsService.open.bind(wsService),
close: wsService.close.bind(wsService),
reconnect: wsService.reconnect.bind(wsService),
on: wsService.on.bind(wsService),
send: wsService.send.bind(wsService)
};
import useWebSocket from '@/utils/websocket';//引入websocket.ts文件
import config from '@/config' //引入公共配置文件
const wsOptions = {
url: config.wbBaseURL,
};
const { open, close, reconnect, on, send } = useWebSocket(wsOptions);
onMounted(() => {
open();//在onMounted钩子中调用open函数,链接websocket
// 注册消息接收处理函数
on('message', (data) => {
receivedMessage = data;
console.log(data)
});
});
示例5:参考vue3中使用webstocket_vue3 封装websocket.ts-CSDN博客https://blog.csdn.net/irisMoon06/article/details/137522205 示例6:vue3 封装WebSocket(直接复制)_vue3 websocket封装-CSDN博客https://blog.csdn.net/wsdshdhdhd/article/details/136008929