随着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
版权归原作者 兴诚 所有, 如有侵权,请联系我们删除。