随着Web应用程序的发展,越来越多的人开始利用Websocket技术来构建实时应用程序。Websocket是一种在客户端和服务器之间建立持久连接的协议。这种协议可以在一个单独的连接上实现双向通信。与HTTP请求-响应模型不同,Websocket允许服务器自主地向客户端发送数据。这种实时连接的能力使得Websocket在许多应用场景中得到了广泛的应用。
Websocket技术的优点之一是减少了网络延迟。在传统的HTTP请求-响应模型中,客户端必须不断地向服务器发送请求以获取更新的数据。这种不断的请求-响应循环会占用大量的带宽和处理能力。而Websocket的持久连接可以在服务器有新数据时立即向客户端发送,从而减少了网络延迟和服务器负载。
另一个优点是Websocket可以处理大量的并发连接。在传统的HTTP请求-响应模型中,每个请求都必须在服务器上进行处理,这可能会对服务器造成负载压力。但是,Websocket的持久连接可以在服务器上保持打开状态,从而减少了与每个连接相关的开销。这使得服务器可以处理大量的并发连接而不会降低性能。
Websocket还可以用于实时通信。例如,聊天应用程序可以使用Websocket来实现实时消息传递。在这种情况下,Websocket的持久连接可以在服务器上保持打开状态,以便客户端可以接收实时消息。这种实时通信的能力使得Websocket在许多应用程序中得到了广泛的应用。
总之,Websocket技术在现代Web应用程序中发挥着越来越重要的作用。它可以减少网络延迟和服务器负载,处理大量的并发连接,并提供实时通信能力。因此,如果您正在构建一个需要实时更新的Web应用程序,那么Websocket技术可能是您的理想选择。
封装类实现
import { WebSocketConfigOption } from './WebSocketConfigOption'; export class ReconnectableWebSocket { private ws!: WebSocket; // ws实例 private opt: WebSocketConfigOption; // ws配置项 private lockReconnect: boolean = false; // 避免ws重复连接 private isClosingWindow: boolean = false; private reconnectTimeout: any; private heartSendInterval: any; constructor(option: WebSocketConfigOption) { if (null === option.url || '' === option.url) { throw ('url不能为空'); } this.opt = option; this.initWebSocket(); } private initWebSocket() { if (null == this.opt.secWebSocketProtocol) { this.ws = new WebSocket(this.opt.url); } else if (this.opt.secWebSocketProtocol.length == 0) { this.ws = new WebSocket(this.opt.url); } else { this.ws = new WebSocket(this.opt.url, this.opt.secWebSocketProtocol); } this.initEventHandle(); window.onbeforeunload = () => { this.isClosingWindow = true; this.ws.close(); // 当窗口关闭时,主动去关闭websocket连接。 } } private initEventHandle() { this.ws.onclose = () => { console.log('ws连接关闭!' + this.opt.url); this.opt.onclose && this.opt.onclose(); this.heartCheckStop(); if (!this.isClosingWindow) { this.reconnect(); } } this.ws.onerror = () => { console.log('ws连接错误!' + this.opt.url); this.opt.onerror && this.opt.onerror(); this.heartCheckStop(); if (!this.isClosingWindow) { this.reconnect(); } } this.ws.onopen = () => { console.log('ws连接成功!' + this.opt.url); this.opt.onopen && this.opt.onopen(); this.heartCheckStart(); } this.ws.onmessage = (event: any) => { this.opt.onmessage && this.opt.onmessage(event); } } /** 重连 */ private reconnect() { if (this.lockReconnect) { return; } this.lockReconnect = true; this.reconnectTimeout = setTimeout(() => { this.initWebSocket(); this.lockReconnect = false; }, 2000); } /** 关闭重连 */ private reconnectStop(): void { clearTimeout(this.reconnectTimeout); } /** 开启心跳包保持连接 */ private heartCheckStart(): void { this.ws.send('heartCheck'); this.heartSendInterval = setInterval(() => { this.ws.send('heartCheck'); }, 5 * 60 * 1000); } /** 关闭心跳包 */ private heartCheckStop(): void { clearInterval(this.heartSendInterval); } /** 主动关闭连接 */ public close(): void { this.reconnectStop(); this.heartCheckStop(); this.isClosingWindow = true; this.ws.close(); } }
配置类实现
export type WebSocketConfigOption = { url: string; secWebSocketProtocol?: Array<string>; onopen?: () => void; onmessage?: (msg: any) => void; onerror?: () => void; onclose?: () => void; }
应用示例
import { WebSocketConfigOption } from '../websocket/WebSocketConfigOption'; import { ReconnectableWebSocket } from '../websocket/ReconnectableWebSocket'; import { InnerMqService } from '../../rx/inner-mq.service'; export class MapMessageConnection { private ws!: ReconnectableWebSocket; constructor( private path: string, private innerMqService: InnerMqService, ) { this.connection(); } /** 连接 */ private connection(): void { let wsConfig: WebSocketConfigOption = { url: this.path, onopen: () => { }, onerror: () => { }, onmessage: (msg: any) => { if (msg.data && msg.data !== '') { let data = JSON.parse(msg.data); this.innerMqService.pub(data.title, data.content); } } } this.ws = new ReconnectableWebSocket(wsConfig); } /** 断开连接 */ public disConnection(): void { this.ws.close(); } }
import { InnerMqClient } from '../../rx/inner-mq.service'; import { SubmitService } from '../../service/submit.service'; import { MapBase } from '../../map/map-base'; import { CommonUtil } from '../../util/common-util'; import { MapPage } from '../../view/page/map/map.page'; import { MapDraw } from '../../map/draw/map-draw'; import { MapWrap } from '../../map/draw/map-wrap'; import { GeoUtil } from "../../map/geo-util"; import { Point } from "../../map/entity/Point"; export class MapMessageProcessor { constructor( private mqClient: InnerMqClient, private submitService: SubmitService, private mapBase: MapBase, private mapPage: MapPage, ) { /** 放大 */ mqClient.sub('ZoomIn').subscribe((res) => { mapBase.zoomIn(); }); /** 缩小 */ mqClient.sub('ZoomOut').subscribe((res) => { mapBase.zoomOut(); }); /** 拖动 */ mqClient.sub('Pan').subscribe((res) => { mapBase.pan(); }); /** 显示网格 */ mqClient.sub('GridSwitch').subscribe((res) => { let update; if (mapBase.getGridVisible()) { mapBase.closeGrid(); update = false; } else { mapBase.showGrid(); update = true; } let config = mapBase.getMapConfig(); if (config) { config.grid = update; CommonUtil.setConfigCache(config); mapBase.setMapConfig(config); } }); /** 切换图层源 */ mqClient.sub('SwitchResource').subscribe((res) => { // 切换图层 debugger let lastType = mapBase.getCurrentCoordinateType(); mapBase.switchMapResource(res); let currentType = mapBase.getCurrentCoordinateType(); // 保存设置 let config = mapBase.getMapConfig(); if (config) { config.layer = res; CommonUtil.setConfigCache(config); mapBase.setMapConfig(config); } // 检查坐标类型 if (lastType != currentType) { if (lastType == 'wgs84' && currentType == 'gcj02') { mapBase.turnMapFeaturesFromWgs84ToGcj02(); } else if (lastType == 'gcj02' && currentType == 'wgs84') { mapBase.turnMapFeaturesFromGcj02ToWgs84(); } } // 回调 setTimeout(() => { mapPage.updateShowInfo(); }); }); /** 绘制类型切换 - */ mqClient.sub('SwitchDrawType').subscribe((res) => { mapBase.setDrawType(res); }); /** 绘制 - */ mqClient.sub('OpenDraw').subscribe((res) => { mapBase.pan(); mapBase.removeDrawedFeatures(); mapBase.openDraw({ drawEnd: () => { setTimeout(() => { mapBase.removeDrawInteraction(); }) }, modifyEnd: () => { } }); }); /** 绘制指定多边形并定位 - */ mqClient.sub('DrawPolygonAndPositioning').subscribe((res) => { mapBase.pan(); mapBase.removeDrawedFeatures(); let blocks = JSON.parse(res); for (let i = 0; i < blocks.length; i++) { let points: Array<Point> = []; for (let j = 0; j < blocks[i].length; j++) { let point = new Point(blocks[i][j].lng, blocks[i][j].lat); if (mapBase.getCurrentCoordinateType() == 'wgs84') { points.push(GeoUtil.gcj02_To_wgs84(point)); } else { points.push(point); } } let feature = MapDraw.createPolygonFeature(points); MapWrap.addFeature(mapBase, mapBase.drawLayerName, feature); } mapBase.setFitviewFromDrawLayer(); }); /** fitview - */ mqClient.sub('Fitview').subscribe((res) => { mapBase.setFitviewFromDrawLayer(); }); /** 删除绘制 - */ mqClient.sub('RemoveDrawedShape').subscribe((res) => { mapBase.removeDrawedFeatures(); }); /** 提交区块下载 - */ mqClient.sub('SubmitBlockDownload').subscribe((res) => { let data = { tileName: this.mapBase?.getCurrentXyzName(), mapType: CommonUtil.getMapType(this.mapBase?.getCurrentXyzName()), tileUrl: this.mapBase?.getCurrentXyzUrlResources(), points: this.mapBase?.getDrawedPoints(), }; this.submitService.blockDownload(data).then((r) => { }); }); /** 提交世界下载 - */ mqClient.sub('SubmitWorldDownload').subscribe((res) => { let data = { tileName: this.mapBase?.getCurrentXyzName(), mapType: CommonUtil.getMapType(this.mapBase?.getCurrentXyzName()), tileUrl: this.mapBase?.getCurrentXyzUrlResources() }; this.submitService.worldDownload(data).then((r) => { }); }); } }
如果对您有帮助
感谢支持技术分享,请点赞支持:
技术合作交流qq:2401315930