概述

web管理系统中可以对业务数据执行新增和删除,现在需要当业务数据发生新增或删除操作后,尽可能实时的反应到WPF客户端上面。

web管理系统用VUE编写,后端服务为SpringBoot,WPF客户端基于.Netframework4.8编写。

整体架构

sequenceDiagram
title: 交互时序图

web前台->>+web后端服务:新增数据
 Note over web前台,web后端服务:caremaId,labelInfo,......

web后端服务->>+WebSocketServer:创建websocker消息
 Note over web后端服务,WebSocketServer:Must:cameraId=clientId

WPF客户端1-->>+WebSocketServer:创建监听
Note over WPF客户端1,WebSocketServer:clientId

WPF客户端2-->>+WebSocketServer:创建监听
Note over WPF客户端2,WebSocketServer:clientId

WebSocketServer->>WPF客户端1:分发websocker消息
 Note over WebSocketServer,WPF客户端1:依据:cameraId=clientId

WebSocketServer->>WPF客户端2:分发websocker消息
 Note over WebSocketServer,WPF客户端2:依据:cameraId=clientId

设计

流程设计

  • 用户在浏览器界面执行新增业务数据操作,调用后端新增接口
  • WPF客户端在启动的时候初始化websocket客户端,并创建对server的监听
  • 后端新增接口先将数据落库,而后调用websocket服务端产生消息,消息在产生后立马被发送到了正在监听中的websocket-client
  • websocket-server和websocket-client是一对多的关系,如何保证业务数据被正确的分发?监听的时候给server端传递一个全局唯一的clientId,业务数据在产生的时候关联到一个BizId上面,只要保证clientId=BizId就可以了。
  • 删除流程和新增类似

程序设计

WebSocketServer

概述

WebSocketServer端采用SpringBoot双色球129期开奖结果 实现,通过在springboot-web项目中集成 org.springframework.boot:spring-boot-starter-websocket

实现websocket的能力。

新增pom



<!--  websocket  -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

新增配置类



import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.socket.config.annotation.EnableWebSocket;

import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
@EnableWebSocket
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

创建websocket端点



import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap; @ServerEndpoint("/ws/label/{clientId}")
@Component
public class LabelWebSocket {
    /**
     * session list
     */
    private static ConcurrentHashMap<String, Session> sessionList = new ConcurrentHashMap<>();
    /**
     * 当前 clientId
     */
    private String currentClientId = "";
    @OnOpen
    public void open(Session session, @PathParam("clientId") String clientId) throws IOException {
        if (sessionList.containsKey(clientId)) {
            sessionList.remove(clientId);
        }
        sessionList.put(clientId, session);
        currentClientId = clientId;
        this.sendMsg(session, "connectok");
    }
    @OnClose
    public void close(Session session) throws IOException {
        sessionList.remove(currentClientId);
        System.out.println("连接关闭,session=" + JSON.toJSONString(session.getId()));
    }
    @OnMessage
    public void receiveMsg(Session session, String msg) throws IOException {
        this.sendMsg(session, "接收到的消息为:" + msg);
//        throw new RuntimeException("主动抛异常");
    }
    @OnError
    public void error(Session session, Throwable e) throws IOException {
        System.out.println("连接异常,session=" + JSON.toJSONString(session.getId()) + ";currentClientId=" + currentClientId);
        this.sendMsg(session, "发生异常,e=" + e.getMessage());
        e.printStackTrace();
    }
    /**
     * @param clientId
     * @param msg
     */
    public boolean sendMsg(String clientId, String msg) throws IOException {
        if (sessionList.containsKey(clientId)) {
            Session session = sessionList.get(clientId);
            this.sendMsg(session, msg);
            return true;
        } else {
            return false;
        }
    }
    private void sendMsg(Session session, String msg) throws IOException {
        session.getBasicRemote().sendText(msg);
    }
}

WebSocketClient

概述

WebSocketClient端集成在WPF应用客户端中,通过前期调研,选中 WebSocketSharp 作为websocketclient工具,WebSocketSharp 是托管在Github的开源项目,MITLicense,目前4.9K的star。

安装WebSocketSharp


//nuget Install-Package WebSocketSharp -Pre

初始化client


WebSocket ws = new WebSocket("ws://127.0.0.1:8083/ws/xx/clientId");

创建连接



private void InitWebSocket()
{
    ws.OnOpen += (sender, e) =>
    {
        Console.WriteLine("onOpen");
    };
    //允许ping
    ws.EmitOnPing = true;
    //接收到xiaoxi
    ws.OnMessage += (sender, e) =>
    {
        ReceiveMessage(sender, e);
    };
    ws.Connect();
//发送消息
    //ws.Send("BALUS")
    ;
}
private void ReceiveMessage(object sender, MessageEventArgs e)
{
    if (e.IsText)
    {
        // Do something with e.Data.like jsonstring
        Console.WriteLine(e.Data);
        return;
    }
    if (e.IsBinary)
    {
        // Do something with e.RawData. like  byte[]
        return;
    }
    if (e.IsPing)
    {
        // Do something to notify that a ping has been received.
        return;
    }
}

接口设计

新增接口

概述

目前WebSocketServer和web后端服务是在同一个SpringBoot的工程中,所以只要将WebSocketServer托管到SpringContainer中,web后端服务可以通过 DI 的方式直接访问 WebSocketEndPoint。

如果考虑程序的低耦合,可以在WebSocketServer和web后端服务之间架设一个MQ。

核心代码


    @Autowired
    private LabelWebSocket ws;
    @GetMapping("/create")
    public boolean createLabel() throws IOException {
        String cameraId = "cml";
        //todo
        boolean result = ws.sendMsg(cameraId, "新增标签");
        return result;
    }

风险

分布式风险

当前在 WebSocketServer 中,已经连接的client信息是记录在当前双色球 的cache中,如果服务做横向扩容,cache信息无法在多实例双色球 中传递,将导致无法正确的处理业务数据,并可能会发生意想不到的异常和bug,此问题在并发越高的情况下造成的影响越大

资源风险

web后端服务为基于java语言的springboot程序,这种类型程序的特点是内存消耗特别严重。WebSocketServer服务在本项目中仅用作消息中间件,连通web后端服务和WPF客户端。

首先WebSocketServer没有太多的计算能力的消耗,内存消耗会随着连接客户端数量的增长而增长,网络将是最大的开销,一方面需要转发来自web后端服务的业务数据,并和WPF客户端保持长连接;另一方面WebSocketServer和WPF客户端的交互可能会走公网,而其和web后端服务必然是在局域网环境。

综上,将web后端服务和WebSocketServer分开部署对于硬件资源成本和利用率来说是最好的选择。

高可用风险

未引入重试机制,当某一个环节失败之后,将导致异常情况发生。

基于WebSocket的实时消息传递设计的更多相关文章

  1. Socket.IO – 基于 WebSocket 构建跨浏览器的实时应用

     Socket.IO 是一个功能非常强大的双色球129期开奖结果 ,能够帮助你构建基于 WebSocket 的跨浏览器的实时应用.支持主流浏览器,多种平台,多种传输模式,还可以集合 Exppress 双色球129期开奖结果 构建各种功能复杂 ...

  2. 基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(二)

    我们上一篇<基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)>主要讲解了如何搭建一个实时数据通讯服务器,客户端与服务端是如何通讯的,相信通过上一篇的讲解,再配 ...

  3. 基于MATLAB的GUI(Graphical User Interface)音频实时显示设计

    摘要:本文章的设计主要讲基于matlab的gui音频实时显示设计,此次设计的gui相当于一个简洁的音乐播放器,界面只有”录音“和”播放“两个控件,哈哈,够简洁吧.通过”录音“按钮可以实现声音从电脑的声 ...

  4. 基于 WebSocket 构建跨浏览器的实时应用

    Socket.IO – 基于 WebSocket 构建跨浏览器的实时应用 Socket.IO 是一个功能非常强大的双色球129期开奖结果 ,能够帮助你构建基于 WebSocket 的跨浏览器的实时应用.支持主流浏览器,多 ...

  5. 基于 WebSocket 的 MQTT 移动推送方案

    WebSphere MQ Telemetry Transport 简介 WebSphere MQ Telemetry Transport (MQTT) 是一项异步消息传输协议,是 IBM 在分析了他们 ...

  6. 网络编程-基于Websocket聊天室(IM)系统

    目录 一.HTML5 - Websocket协议 二.聊天室(IM)系统的设计 2.1.使用者眼中的聊天系统 2.2.开发者眼中的聊天系统 2.3.IM系统的特性 2.4.心跳机制:解决网络的不确定性 ...

  7. Go实现基于WebSocket的弹幕服务

    拉模式和推模式 拉模式 1.数据更新频率低,则大多数请求是无效的 2.在线用户量多,则服务端的查询负载高 3.定时轮询拉取,实时性低 推模式 1.仅在数据更新时才需要推送 2.需要维护大量的在线长连接 ...

  8. Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G

    code&monkey   Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...

  9. [转]使用 HTML5 WebSocket 构建实时 Web 应用

    HTML5 WebSocket 简介和实战演练 本文主要介绍了 HTML5 WebSocket 的原理以及它给实时 Web 开发带来的革命性的创新,并通过一个 WebSocket 服务器和客户端的案例 ...

  10. 使用 HTML5 WebSocket 构建实时 Web 应用

    原文地址://www.ibm.com/developerworks/cn/web/1112_huangxa_websocket/ HTML5 WebSocket 简介和实战演练 本文主要介绍 ...

随机推荐

  1. 齐博x1内容评论标签的风格制作

    评论的标签如下: {qb:comment name="xxxxx" rows='5'} HTML代码片段 {/qb:comment} 评论涉及到的元素有{posturl} 这个是代 ...

  2. golang中的一些实用功能

    0.1.索引 //waterflow.link/articles/1663921524839 通过使用一些通用代码来节省时间,而无需单独实现它们.以下是一些开发中经常会用到的函数实现的列表 ...

  3. Tensorflow Lite从入门到精通

    TensorFlow Lite 是 TensorFlow 在移动和 IoT 等边缘设备端的解决方案,提供了 Java.Python 和 C++ API 库,可以运行在 Android.iOS 和 Ra ...

  4. Android开发 对接微信分享SDK总结

    原文:Android开发 对接微信分享SDK总结 - Stars-One的杂货小窝 公司项目需要对接微信分享,本来之前准备对接友盟分享的,但友盟的分享实际参数太多,而我又只需要对接一个微信分享,于是便 ...

  5. Codeforces Global Round 18 B. And It's Non-Zero(按位前缀和)

    题目大意:求一段数(l到r)的按位与结果不为零需要删除中间元素的最小个数 思路:按位与使得结果不为0只要有某一位全是1即可,所以只要统计每一位1的个数,用总个数减去1的个数就是某一位0的个数 删除包含 ...

  6. C# 获取打开的EXCEL中某列的行数

    背景 在通过C#操作EXCEL时 获取行数 int iRowCount = worksheet.get_Range("A65535", oMissing).get_End(MExc ...

  7. Seata Server 1.5.2 源码学习

    Seata 包括 Server端和Client端.Seata中有三种角色:TC.TM.RM,其中,Server端就是TC,TM和RM属Client端.Client端的源码学习上一篇已讲过,详见 < ...

  8. 匿名方法、Lambda表达和自定义泛型委托以及Func、Action系统泛型委托

    1.匿名方法的概念:一个方法没有具体的名称,而只有关键字delegate.方法参数.方法体.这种方法是匿名方法. 匿名方法的好处:将具体方法和委托直接关联在一起,如果我们基于委托只需要一个方法的时候, ...

  9. Java标准类

    一个标准的类通常要拥有以下四个组成部分 1.所有的成员变量都要使用private关键字修饰 2.为每一个成员变量编写一对儿Getter/Setter方法 3.编写一个无参数的构造方法 4.编写一个全参 ...

  10. requests模块/openpyxl模块/简单爬虫实战

    内容概要 第三方模块的下载及使用 网络爬虫及requests模块 网络爬虫实战爬取二手房信息 自动化办公领域模块openpyxl 练习题及答案 第三方模块的下载 第三方模块就类似与别人写好的模块,我们 ...