关于推送后台的webapi demo
文章目录
-
目录
系列文章目录
文章目录
前言
一、如何实现推送的思考
二、使用步骤
1.引入库
2.连接方法
3. 发送数据
4.结束时发的消息
5.相关的类
总结
前言
手机app一般都有接收消息推送的功能,比如美团app 点的外卖订单推送,那么对于后台如何将消息推送到手机app,此处我使用的是.net framework框架
一、如何实现推送的思考
介于推送是实时获取的,所以我们需要实时推送,所以这里使用websocket 方式 ,而不是http协议,另外我们可能会长时间保持一个连接,以避免频繁地建立连接,但同时,一般会有一个超时时间,在这个时间内没发起任何请求的连接会被断开,以减少负载,节约资源,就需要一个心跳包,心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包。 用来判断对方(设备,进程或其它网元)是否正常运行,采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经离线,总结下就是我们需要一个连接websocket 的连接方法,和发送消息的方法,还有一个心跳包,还有消息发送结束时也要发送一个消息
二、使用步骤
1.引入库
代码如下(示例):
using ES.Web.Api.Dto.Socket;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web;
using System.Web.Http;
using System.Web.UI.WebControls;
using Xhxx.Entity;
using Xhxx.Utils;
using Xhxx.WebSockets;
2.连接方法
代码如下(示例):
public HttpResponseMessage Connect(string nickName){var webSocketHandler = new WebSocketHandler();if (_handlers.ContainsKey(nickName)){return Request.CreateResponse(HttpStatusCode.BadRequest);}_handlers[nickName] = webSocketHandler;webSocketHandler.TextMessageReceived += (sendor, Parameter) =>{try{WebSocketDto _para = Newtonsoft.Json.JsonConvert.DeserializeObject<WebSocketDto>(Parameter);if (_para == null){_handlers.Remove(nickName);result.code = (int)Const.c_code.参数错误;result.message = Const.c_code.参数错误.ToString();SendMessage(nickName, result.ToJson());}else{_para.nickName = nickName;if (_para.queryType == (int)QuestType.Agent){DealMainAgent(_para);}if (_para.queryType == (int)QuestType.xintiao){result.code = (int)QuestType.xintiao;result.message = "恭喜,您目前处于活蹦乱跳状态 ^_^ ";SendMessage(nickName, result.ToJson());}}}catch (Exception ex){_handlers.Remove(nickName);result.code = (int)Const.c_code.抛出异常;result.message = ex.Message;SendMessage(nickName, result.ToJson());}};webSocketHandler.Closed += (sendor, arg) =>{if (nickName.Contains("login_")){ClosedLogin(nickName);}_handlers.Remove(nickName);};webSocketHandler.Opened += (sendor, arg) =>{result.message = "连接成功...";SendMessage(nickName, result.ToJson());};HttpContext.Current.AcceptWebSocketRequest(webSocketHandler);return Request.CreateResponse(HttpStatusCode.SwitchingProtocols);}
3. 发送数据
/// <summary>/// 发送数据/// </summary>/// <param name="sendorNickName"></param>/// <param name="message"></param>private void SendMessage(string sendorNickName, string message, bool Broadcast = false){foreach (var handlerKvp in _handlers){if (Broadcast){//广播发送handlerKvp.Value.SendMessage(message).Wait();}else{//点对点发送if (handlerKvp.Key == sendorNickName){handlerKvp.Value.SendMessage(message).Wait();}}}}private void GoSendMessage(WebSocketDto data, dynamic item, string usercode = ""){if (item != null){int workid = 0;int.TryParse(item.WorkID.ToString(), out workid);var Tmessage = new MessageDto{WorkID = workid,FlowName = item.FlowName,Title = item.Title,Fk_Flow = item.FK_Flow,MessageCount = Convert.ToInt32(item.MessageCount),Detail = item};result.code = (int)BackQuestType.BackAgent;result.message = JsonConvert.SerializeObject(Tmessage);SendMessage(data.nickName, result.ToJson());}}
4.结束时发的消息
private void BackOver(WebSocketDto data){//消息推送完result.code = (int)BackQuestType.BackOver;result.message = BackQuestType.BackOver.ToString();SendMessage(data.nickName, result.ToJson());}
5.相关的类
using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.WebSockets;namespace Xhxx.WebSockets;public class WebSocketHandler
{private WebSocket _webSocket;private int frameBytesCount = 10240;public event EventHandler Opened;public event EventHandler<string> TextMessageReceived;public event EventHandler Closed;public virtual async Task ProcessRequest(AspNetWebSocketContext context){_webSocket = context.WebSocket;RaiseOpenEvent();while (_webSocket.State == WebSocketState.Open){List<byte> receivedBytes = new List<byte>();ArraySegment<byte> buffer2 = WebSocket.CreateServerBuffer(frameBytesCount);WebSocketReceiveResult receiveResult = await _webSocket.ReceiveAsync(buffer2, CancellationToken.None);if (receiveResult.MessageType == WebSocketMessageType.Close){await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);RaiseOnClosed();break;}WebSocketMessageType messageType = receiveResult.MessageType;MergeFrameContent(receivedBytes, buffer2.Array, receiveResult.Count);while (!receiveResult.EndOfMessage){buffer2 = WebSocket.CreateServerBuffer(frameBytesCount);receiveResult = await _webSocket.ReceiveAsync(buffer2, CancellationToken.None);MergeFrameContent(receivedBytes, buffer2.Array, receiveResult.Count);}RaiseMessageArrive(receivedBytes.ToArray(), messageType, receivedBytes.Count);}}public virtual async Task SendMessage(string message){if (_webSocket == null || _webSocket.State != WebSocketState.Open){throw new InvalidOperationException("the web socket is not open.");}byte[] bytes = Encoding.UTF8.GetBytes(message);for (int sentBytes = 0; sentBytes < bytes.Length; sentBytes += frameBytesCount){int remainingBytes = bytes.Length - sentBytes;await _webSocket.SendAsync(new ArraySegment<byte>(bytes, sentBytes, (remainingBytes > frameBytesCount) ? frameBytesCount : remainingBytes), WebSocketMessageType.Text, endOfMessage: true, CancellationToken.None);}}protected void MergeFrameContent(List<byte> destBuffer, byte[] buffer, long count){count = ((count < buffer.Length) ? count : buffer.Length);if (count == buffer.Length){destBuffer.AddRange(buffer);return;}byte[] array = new byte[count];Array.Copy(buffer, array, count);destBuffer.AddRange(array);}protected void RaiseOpenEvent(){this.Opened?.Invoke(this, EventArgs.Empty);}protected void RaiseMessageArrive(byte[] buffer, WebSocketMessageType type, long count){if (type == WebSocketMessageType.Text && this.TextMessageReceived != null){this.TextMessageReceived(this, Encoding.UTF8.GetString(buffer));}}protected void RaiseOnClosed(){this.Closed?.Invoke(this, EventArgs.Empty);}
}
using System.Collections.Generic;namespace ES.Web.Api.Dto.Socket
{public class WebSocketDto{/// <summary>/// 类型/// </summary>public int queryType { get; set; }/// <summary>/// 仓号数组/// </summary>public List<string> cfbh { get; set; }/// <summary>/// 测气开始通道/// </summary>public int startChannel { get; set; }/// <summary>/// 测气结束通道/// </summary>public int endChannel { get; set; }/// <summary>/// 测气间隔/// </summary>public int span { get; set; }/// <summary>/// 抽气时间/// </summary>public int cqTime { get; set; }/// <summary>/// 排气时间/// </summary>public int pqTime { get; set; }/// <summary>/// 连接用户/// </summary>public string nickName { get; set; }/// <summary>/// Token/// </summary>public string Token { get; set; }}
}
总结
这就是如何给app推送消息
相关文章:
关于推送后台的webapi demo
文章目录 目录 系列文章目录 文章目录 前言 一、如何实现推送的思考 二、使用步骤 1.引入库 2.连接方法 3. 发送数据 4.结束时发的消息 5.相关的类 总结 前言 手机app一般都有接收消息推送的功能,比如美团app 点的外卖订单推送,那么对于后台如何将消息推…...

中国品牌日 | 以科技创新为引领,激光院“风采”品牌建设结硕果
品牌,作为企业不可或缺的隐形财富,在当今竞争激烈的市场环境中,其构建与强化已成为推动企业持续繁荣的关键基石。为了更好地保护自主研发产品,激光院激光公司于2020年3月7日正式注册“风采”商标,创建拥有自主知识产权…...

GNU Screen 曝多漏洞:本地提权与终端劫持风险浮现
SUSE安全团队全面审计发现,广泛使用的终端复用工具GNU Screen存在一系列严重漏洞,包括可导致本地提权至root权限的缺陷。这些问题同时影响最新的Screen 5.0.0版本和更普遍部署的Screen 4.9.x版本,具体影响范围取决于发行版配置。 尽管GNU Sc…...

05.three官方示例+编辑器+AI快速学习three.js webgl - animation - skinning - ik
本实例主要讲解内容 这个Three.js示例展示了**反向运动学(Inverse Kinematics, IK)**在3D角色动画中的应用。通过加载一个角色模型,演示了如何使用IK技术实现自然的肢体运动控制,如手部抓取物体的动作。 核心技术包括: CCD反向运动学求解器…...
计算机视觉与深度学习 | 激光雷达 vs. RTK+摄像头:谁是智能割草机器人的最优选择?
激光雷达 vs. RTK+摄像头 一、技术原理与核心优势对比二、实际应用中的性能差异三、行业趋势与创新方向四、场景化选择建议五、未来展望激光雷达与RTK+摄像头是智能割草机器人领域两种主流技术路线,各有其适用场景与优劣势。结合行业最新动态与技术演进,以下从多个维度对比分…...

第29节:现代CNN架构-Inception系列模型
引言 Inception系列模型是卷积神经网络(CNN)发展历程中的重要里程碑,由Google研究人员提出并不断演进。这一系列模型通过创新的架构设计,在保持计算效率的同时显著提升了图像识别任务的性能。从最初的Inception v1到最新的Inception-ResNet,每一代Inception模型都引入了突破…...

【深度学习】将本地工程上传到Colab运行的方法
1、将本地工程(压缩包)上传到一个新的colab窗口:如下图中的 2.zip,如果工程中有数据集,可以删除掉。 2、解压压缩包。 !unzip /content/2.zip -d /content/2 如果解压出了不必要的文件夹可以递归删除: #…...

RabbitMQ 中的六大工作模式介绍与使用
文章目录 简单队列(Simple Queue)模式配置类定义消费者定义发送消息测试消费 工作队列(Work Queues)模式配置类定义消费者定义发送消息测试消费负载均衡调优 发布/订阅(Publish/Subscribe)模式配置类定义消…...

Android HttpAPI通信问题(已解决)
使用ClearTextTraffic是Android中一项重要的网络设置,它控制了应用程序是否允许在不使用HTTPS加密的情况下访问网络。在默认情况下,usescleartexttraffic的值为true,这意味着应用程序可以通过普通的HTTP协议进行网络通信。然而,这样的设置可能会引发一些安全问题,本文将对…...

【SSM-SpringMVC(二)】Spring接入Web环境!本篇开始研究SpringMVC的使用!SpringMVC数据响应和获取请求数据
SpringMVC的数据响应方式 页面跳转 直接返回字符串通过ModelAndView对象返回 回写数据 直接返回字符串返回对象或集合 页面跳转: 返回字符串方式 直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转 RequestMapping("/con&…...

docker安装mysql8, 字符集,SQL大小写规范,sql_mode
一、Docker安装MySQL 使用Docker安装MySQL,命令如下 docker run -d \-p 3306:3306 \-v mysql_conf:/etc/mysql/conf.d \-v mysql_data:/var/lib/mysql \--name mysql \--restartalways \--privileged \-e MYSQL_ROOT_PASSWORD1234 \mysql:8.0.30参数解释 🐳 dock…...
FastMCP v2:构建MCP服务器和客户端的Python利器
FastMCP v2:构建MCP服务器和客户端的Python利器 引言 在人工智能与大语言模型(LLMs)的应用场景中,如何高效地构建服务器和客户端以实现数据交互与功能调用是关键问题。Model Context Protocol (MCP) 为此提供了一种标准…...
一个WordPress连续登录失败的问题排查
文章目录 1. 问题背景2. 解决方案搜索3. 问题定位4. 排查过程5. 清理空间6. 处理结果7. 后续优化 1. 问题背景 登录请求URL: Request URL: https://www.xxxxxx.com/wp-login.php 返回的响应头信息是: location: https://www.xxxxxx.com/wp-admin/ 证明登录成功。 接下来浏览器…...

【SSM-SSM整合】将Spring、SpringMVC、Mybatis三者进行整合;本文阐述了几个核心原理知识点,附带对应的源码以及描述解析
SSM整合的基础jar包 需要创建的层级: controller层 该层下需要创建对应的控制器Servlet POJO文件夹 该层下需要创建与数据库对应的POJO类 mapper层 该层下需要创建Mapper的接口实现 service层 该层下需要创建业务层的接口及其接口实现 需要创建的配置文件&#x…...
Go语言超时控制方案全解析:基于goroutine的优雅实现
一、引言 在构建高可靠的后端服务时,超时控制就像是守护系统稳定性的"安全阀",它确保当某些操作无法在预期时间内完成时,系统能够及时止损并释放资源。想象一下,如果没有超时控制,一个简单的数据库查询卡住…...
spark运行架构及核心组件介绍
目录 1. Spark 的运行架构1.1 Driver1.2 Executor1.3 Cluster Manager1.4 工作流程 2. Spark 的核心组件2.1 Spark Core2.2 Spark SQL2.3 Spark Streaming2.4 MLlib2.5 GraphX 3. Spark 架构图4. Spark 的优势4.1 高性能4.2 易用性4.3 扩展性4.4 容错性 5. 总结 1. Spark 的运行…...
idea中编写spark程序
### 在 IntelliJ IDEA 中配置和编写 Spark 程序 要在 IntelliJ IDEA 中高效地开发 Spark 程序,需要完成一系列必要的环境配置以及项目搭建工作。以下是详细的说明。 --- #### 1. 安装与配置 IntelliJ IDEA 为了确保 IDE 可以支持 Scala 开发,首先需要…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(21):复习
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(21):复习 1、前言(1)情况说明(2)工程师的信仰 2、知识点(1)じょうけん 条件形1、復習 (&#x…...

MYSQL数据库集群高可用和数据监控平台
项目环境 项目拓扑结构 软硬件环境清单 软硬件环境清单 软硬件环境清单 主机名IP硬件软件 master1 192.168.12.130 VIP:192.168.12.200 cpu:1颗2核 内 存:2GB HDD:20GB 网 络:NAT VmWare17 OpenEuler22.03 SP4 MySql8.0.3…...
Spark SQL 读取 CSV 文件,并将数据写入 MySQL 数据库
在 Spark 中,可以使用 Spark SQL 读取 CSV 文件,并将数据写入 MySQL 数据库。以下是一个完整的示例,展示如何实现这一过程。 环境准备 安装 MySQL:确保 MySQL 数据库已安装并运行。创建 MySQL 数据库和表:CREATE DAT…...
C++矩阵操作:正交矩阵(旋转矩阵)
文章目录 一、简介二、实现代码三、实现效果一、简介 我们知道判断一个矩阵的正交性可以看它是否符合以下条件: R T R = I R^TR=I R...
基于单片机的车灯智能控制系统设计与实现
标题:基于单片机的车灯智能控制系统设计与实现 内容:1.摘要 随着汽车行业的快速发展,车灯的智能化控制成为提升行车安全和驾驶体验的关键因素。本文旨在设计并实现一种基于单片机的车灯智能控制系统。采用单片机作为控制核心,结合光照传感器、雨滴传感器…...
机器学习第十一讲:标准化 → 把厘米和公斤单位统一成标准值
机器学习第十一讲:标准化 → 把厘米和公斤单位统一成标准值 资料取自《零基础学机器学习》。 查看总目录:学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章:DeepSeek R1本地与线上满血版部署:超详细手把手指南 一、买菜…...

uni-app vue3版本打包h5后 页面跳转报错(uni[e] is not a function)
先看问题 解决方案 在HBuilderX项目中,若需在Web配置中显式关闭摇树优化(Tree Shaking),可以通过以下步骤实现:首先,在配置中打开摇树优化,然后再将其关闭。这样操作后,配置文件中会…...
大二java第一面小厂(挂)
第一场: mybatis怎么防止数据转义。 Hutool用的那些你常用的方法。 springboot的常用注解。 redis的多级缓存。 websocket怎么实现的多人协作编辑功能。 怎么实现的分库分表。 mysql里面的各种操作,比如说分表怎么分,分页查询怎么用。 mybat…...

【Redis】缓存穿透、缓存雪崩、缓存击穿
1.缓存穿透 是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,导致请求直接穿透缓存到达数据库,给数据库带来压力的情况。 常见的解决方案有两种: 缓存空对象:实现简单,维护方便&am…...
双目云台摄像机:双摄安防功能全方位
双目云台摄像机是一种具有革命性设计的云台摄像机设备,其核心在于其独特的双摄像头配置。以下是对这种先进安防设备的详细介绍: 一、核心原理 双目云台摄像机的核心原理在于利用两个摄像头从不同角度捕捉同一场景,通过先进的算法计算两个图…...

告别数据僵尸!Redis实现自动清理过期键值对
在这个数据爆炸的时代,内存就像珍贵的土地资源,而Redis则是这片土地上的智能管家。它不仅能高效存储数据,还能像秋叶定时凋零般,让键值对在指定时间自动消失。今天,就让我们揭开这项"数据保鲜"技术的奥秘。 …...

web第三次课后作业--基于JDBC对mysql数据库的增删查改操作
一、工程搭建步骤 1.新建java项目,添加jdbc依赖 2.写java程序 3.添加mysql数据源,连接本地数据库 4.运行程序二、运行结果 三、代码 代码解析 加载数据驱动 try {Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundExceptio…...
《P2345 [USACO04OPEN] MooFest G》
题目背景 P5094 [USACO04OPEN] MooFest G 加强版 题目描述 约翰的 n 头奶牛每年都会参加“哞哞大会”。 哞哞大会是奶牛界的盛事。集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。 它们参加活动时会聚在一起,第 i 头…...