Winform中使用Websocket4Net实现Websocket客户端并定时存储接收数据到SQLite中

场景

SpringBoot+Vue整合WebSocket实现前后端消息推送:

SpringBoot+Vue整合WebSocket实现前后端消息推送_websocket vue3.0 springboot 往客户端推送-CSDN博客

上面实现ws推送数据流程后,需要在windows上使用ws客户端定时记录收到的数据到文件中,这里

文件使用SQLite数据库进行存储。

Winform中操作Sqlite数据增删改查、程序启动时执行创建表初始化操作:

Winform中操作Sqlite数据增删改查、程序启动时执行创建表初始化操作_winform sqllite-CSDN博客

Sqlite的操作参考如上。

注:

博客:
霸道流氓气质_C#,架构之路,SpringBoot-CSDN博客

实现

1、引入WebSocket4Net依赖

使用Nuget搜索并安装WebSocket4Net

2、设计页面布局如下

3、websocket客户端实现

声明客户端对象

public static WebSocket4Net.WebSocket webSocket4NetClient = null;

ws连接按钮的点击事件中

            try {
                var wsAddresss = textBox_ws_address.Text.Trim();
                webSocket4NetClient = new WebSocket4Net.WebSocket(wsAddresss);
                webSocket4NetClient.Opened += WebSocket4Net_Opened;
                webSocket4NetClient.Error += Websocket_Error;
                webSocket4NetClient.Closed += new EventHandler(Websocket_Closed);
                webSocket4NetClient.MessageReceived += WebSocket4Net_MessageReceived;
                webSocket4NetClient.Open();
                textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":ws开始连接");
                textBox_log.AppendText("\r\n");
            } catch (Exception exception) {
                textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":ws连接异常:"+ exception.Message);
                textBox_log.AppendText("\r\n");
            }

这里未添加对ws地址的校验,只关注中间ws相关的代码

                webSocket4NetClient = new WebSocket4Net.WebSocket(wsAddresss);
                webSocket4NetClient.Opened += WebSocket4Net_Opened;
                webSocket4NetClient.Error += Websocket_Error;
                webSocket4NetClient.Closed += new EventHandler(Websocket_Closed);
                webSocket4NetClient.MessageReceived += WebSocket4Net_MessageReceived;
                webSocket4NetClient.Open();

然后编写其各种事件的具体实现。

实现方法中具体逻辑根据业务进行确定。

建立连接事件实现

        private void WebSocket4Net_Opened(object sender, EventArgs e)
        {
            //允许跨线程调用
            Control.CheckForIllegalCrossThreadCalls = false;
            textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":ws建立连接成功");
            textBox_log.AppendText("\r\n");
            //向服务端发送消息
            //webSocket4NetClient.Send("Client准备发送数据!");
        }

收到消息事件实现

        private void WebSocket4Net_MessageReceived(object sender, MessageReceivedEventArgs e)
        {
            //允许跨线程调用
            Control.CheckForIllegalCrossThreadCalls = false;
            //textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":收到消息:");
            //textBox_log.AppendText("\r\n");
            receviceString = e.Message;
        }

出错事件实现

        private void Websocket_Error(object sender, EventArgs e)
        {
            //允许跨线程调用
            Control.CheckForIllegalCrossThreadCalls = false;
            textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Websocket_Error:"+e);
            textBox_log.AppendText("\r\n");
        }

连接关闭事件实现

        private void Websocket_Closed(object sender, EventArgs e)
        {
            //允许跨线程调用
            Control.CheckForIllegalCrossThreadCalls = false;
            textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Websocket_Closed");
            textBox_log.AppendText("\r\n");
        }

ws连接关闭按钮点击实现

        private void button_ws_disconnec_Click(object sender, EventArgs e)
        {
            webSocket4NetClient.Close();
        }

4、定时存储实现

在上面收到消息时将数据赋值给变量

receviceString

声明变量

private string receviceString = String.Empty;

添加Timer定时器

Timer _timer = new Timer();

定时存储按钮点击事件实现

        private void button_start_store_Click(object sender, EventArgs e)
        {
            if (webSocket4NetClient.State != WebSocket4Net.WebSocketState.Open && webSocket4NetClient.State != WebSocket4Net.WebSocketState.Connecting)
            {
                textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Websocket连接异常");
                textBox_log.AppendText("\r\n");
            }
            else {
                //清空数据库
                SQLiteDataReader reader = Global.Instance.sqlLiteHelper.ExecuteQuery("SELECT* FROM positions;");
                if (reader.HasRows)
                {
                    while (reader.Read())
                    {
                        Global.Instance.sqlLiteHelper.ExecuteQuery("DELETE FROM positions WHERE timestamp = " + reader.GetString(reader.GetOrdinal("timestamp")) + ";");
                    }
                }
                _timer.Interval = (int)numericUpDown_rate.Value;
                _timer.Tick += _timer_Tick;
                _timer.Start();
                textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":定时存储已经启动!!");
                textBox_log.AppendText("\r\n");
            }
        }

首先判断ws是否连接上,如果连接上则将库清空,然后获取设置的定时频率并启动定时器

定时器具体实现

        private void _timer_Tick(object sender, EventArgs e) {
            try
            {
                if (webSocket4NetClient.State != WebSocket4Net.WebSocketState.Open && webSocket4NetClient.State != WebSocket4Net.WebSocketState.Connecting)
                {
                    textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Websocket连接异常");
                    textBox_log.AppendText("\r\n");
                }
                else {
                    if (!String.IsNullOrEmpty(receviceString))
                    {
                        //获取ws数据并存储进数据库
                        TimeSpan ts = DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
                        string timeSpan = Convert.ToInt64(ts.TotalSeconds).ToString();
                        //插入数据
                        Global.Instance.sqlLiteHelper.InsertValues("positions", new string[] { timeSpan, receviceString });
                        receviceString = String.Empty;
                    }
                }
            }
            catch (Exception exception)
            {
                textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":定时存储执行异常:" + exception.Message);
                textBox_log.AppendText("\r\n");
            }        
        }

首页也要判断是否连接,然后判断receviceString是否为空,避免ws未传输数据,会定时存储空数据。

不为空则将时间和收到的数据存储进数据库。

停止定时存储按钮点击事件

        private void button_stop_store_Click(object sender, EventArgs e)
        {
            //停止定时器
            _timer.Tick -= _timer_Tick;
            _timer.Stop();
            textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":定时存储已经停止!!!");
            textBox_log.AppendText("\r\n");
            receviceString = String.Empty;
        }

5、运行效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/299927.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SRv6简介

文章目录 SR,分段路由IPv6 SRv6,简单来理解,其实就是 SRIPv6。 SRv6(Segment Routing v6,基于IPv6转发平面的段路由)是基于源路由理念而设计的在网络上转发数据包的一种协议。其核心思想是将报文转发路径切割成不同的段&#xff…

[Linux c/c++] 关于进程名,线程名,/proc文件系统 等

参考: kernel - Why is the name of a process in /proc/PID/status not matching package name or ps command - Stack Overflowhttps://stackoverflow.com/questions/14176058/why-is-the-name-of-a-process-in-proc-pid-status-not-matching-package-name-or-ps…

Opencv与PyQt5设计一个摄像头界面

一、前言 本篇的内容是学习的这一位博主的:程序界面设计_Doc_Cheng的博客-CSDN博客。 这是我见过很详细的教你如何使用的PyQt5来完成UI界面设计的,专注于UI界面设计。对我而言,这教程就像是一个实用工具,因为我只需要能够显示图…

MySQL之视图案例

目录 一.视图1.1 含义1.2 操作 二.案例三.思维导图 一.视图 1.1 含义 虚拟表,和普通表一样使用 1.2 操作 1.创建视图 create view 视图名 as 查询语句; 2.视图的修改 方式一: create or replace view 视图名 as 查询语句 方式二&#x…

H266/VVC率失真优化概述

率失真优化技术 率失真优化: 视频编码的主要目的是在保证一定视频质量的条件下尽量降低视频的编码比特率,或者在一定编码比特率限制条件下尽量地减小编码失真。在固定的编码框架下,为了应对不同的视频内容,往往有多种候选的编码方…

国标28181平台 管理下级推送来的目录资源

目 录 一、业务分组目录和行政区划目录的定义 (一)业务分组目录 (二)行政区划目录 (三)实际应用的目录结构 二、国标28181支持目录资源的推送 三、支持国标28181的视频监控平台…

爬虫-3-模拟登录,代理ip,json模块

#本文仅供学习使用(O`) 如果服务器响应的数据为json数据: 那么我们可以用 res.json() 或 json模块(将json字符串转换为Python里面的字典类型) 接收数据。

关于java的多维数组

关于java的多维数组 在前面的文章中,我们了解了数组的使用,我们之前所了解的数组是一维数组,本篇文章我们来了解一下二维数组,多维数组😀 一、二维数组 首先我们知道一维数组的声明和创建的方式是。 int array ne…

Java面试——框架篇

1、Spring框架中的单例bean是线程安全的吗? 所谓单例就是所有的请求都用一个对象来处理,而多例则指每个请求用一个新的对象来处理。 结论:线程不安全。 Spring框架中有一个Scope注解,默认的值就是singleton,单例的。一…

[算法应用]dijkstra算法的应用

先看一眼原始dijkstra算法,参考自dijkstra算法C实现_c实现djikstra-CSDN博客 分为三步 找到当前最优的把当前最优的,不参与后面的更新逐个比较是否更新 dijkstra算法的应用 题目大概是要从图上找一条权值不减的路径,且要经过最多的点。 所以…

【普中开发板】基于51单片机的简易密码锁设计( proteus仿真+程序+设计报告+讲解视频)

基于51单片机的简易密码锁设计 1.主要功能:资料下载链接: 实物图:2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单 【普中】基于51单片机的简易密码锁设计 ( proteus仿真程序设计报告讲解视频) 仿真图proteus8.16(有低版本) 程…

数据结构——栈(Stack)

目录 1.栈的介绍 2.栈工程 2.1 栈的定义 2.1.1 单链表实现栈 2.1.2 数组实现栈 2.1.2.1 静态数组栈 2.1.2.2 动态数组栈 2.2 栈的函数接口 2.2.1 栈的初始化 2.2.2 栈的数据插入(入栈) 2.2.3 栈的数据删除(出栈) 2.2.…

Kafka_02_Producer详解

Kafka_02_Producer详解 ProducerProducerRecordSend&Close实现原理ProducerInterceptorSerializerPartitioner 事务 Producer Producer(生产者): 生产并发送消息到Broker(推送) Producer是多线程安全的(建议通过池化以提高性能)Producer实例后可发送多条消息(可对应多个P…

组合数据(Python实现)

一、主要目的: 1.熟悉组合数据的类型。 2.掌握列表、元组、字典、集合等组合数据的创建、访问方法。 3.掌握组合数据推导式的使用方法 4.熟悉组合数据的常见应用。 二、主要内容和结果展示: 1. 使用两…

OpenCV中实现图像旋转的方法

OpenCV中实现图像旋转的方法 函数:cv2.flip() 功能:水平或者垂直翻转 格式:dst cv2.flip(src,flipCode[,dst]) 参数说明: src:输入图像 dst:和原图像具有相同大小、类型的目标图像。 flipCode&#…

Python小细节之Gui图形化界面库的对比和选择(一分钟版)

引言 我想要把打包的python程序变得好看 交互起来变得简单 遂 图形化界面 然 相关的库有很多 所以 对比! 开整 8个图形化界面库 在Python中,有多种图形用户界面(GUI)库可以用来创建丰富的图形化应用程序。以下是一些主要的图…

竞赛练一练 第23期:NOC大赛每日一练,python题目刷题第8天,包含答案解析

题目来自:NOC 大赛创客智慧编程赛项Python 复赛模拟题(二) NOC大赛创客智慧编程赛项Python 复赛模拟题(二) 第一题: 编写一个成绩评价系统,当输入语文、数学和英语三门课程成绩时,输出三门课程总成绩及其等级。 (1)程序提示用户输入三个数字,数字分别表示语文、数学、…

3.1 数据链路层概述

目录 3.1 数据链路层概述3.1.1 关于数据链路层什么是数据链路从协议栈看数据链路层数据链路层信道类型 3.1.2 三个基本问题封装成帧透明传输差错控制循环冗余检验CRC(Cyclic Redundancy Check)原理 3.1 数据链路层概述 3.1.1 关于数据链路层 什么是数据…

odoo17 | 模型视图继承

前言 Odoo的强大之处在于它的模块化。模块专门用于满足业务需求,但模块也可以彼此交互。这对于扩展现有模块的功能非常有用。例如,在我们的房地产场景中,我们希望在常规用户视图中直接显示销售人员的属性列表。 但是在讨论特定的Odoo模块继…

HackTheBox - Medium - Linux - UpDown

UpDown UpDown 是一台中等难度的 Linux 机器,暴露了 SSH 和 Apache 服务器。在Apache服务器上,有一个Web应用程序,允许用户检查网页是否已启动。服务器上标识了一个名为“.git”的目录,可以下载以显示目标上运行的“dev”子域的源…
最新文章