关于推送后台的webapi demo

news2025/5/15 18:17:32


文章目录

  • 目录

    系列文章目录

    文章目录

    前言

    一、如何实现推送的思考

    二、使用步骤

    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推送消息

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中国品牌日 | 以科技创新为引领,激光院“风采”品牌建设结硕果

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

GNU Screen 曝多漏洞:本地提权与终端劫持风险浮现

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

05.three官方示例+编辑器+AI快速学习three.js webgl - animation - skinning - ik

本实例主要讲解内容 这个Three.js示例展示了**反向运动学(Inverse Kinematics, IK)**在3D角色动画中的应用。通过加载一个角色模型&#xff0c;演示了如何使用IK技术实现自然的肢体运动控制&#xff0c;如手部抓取物体的动作。 核心技术包括&#xff1a; CCD反向运动学求解器…

第29节:现代CNN架构-Inception系列模型

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

【深度学习】将本地工程上传到Colab运行的方法

1、将本地工程&#xff08;压缩包&#xff09;上传到一个新的colab窗口&#xff1a;如下图中的 2.zip&#xff0c;如果工程中有数据集&#xff0c;可以删除掉。 2、解压压缩包。 !unzip /content/2.zip -d /content/2 如果解压出了不必要的文件夹可以递归删除&#xff1a; #…

RabbitMQ 中的六大工作模式介绍与使用

文章目录 简单队列&#xff08;Simple Queue&#xff09;模式配置类定义消费者定义发送消息测试消费 工作队列&#xff08;Work Queues&#xff09;模式配置类定义消费者定义发送消息测试消费负载均衡调优 发布/订阅&#xff08;Publish/Subscribe&#xff09;模式配置类定义消…

Android HttpAPI通信问题(已解决)

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

【SSM-SpringMVC(二)】Spring接入Web环境!本篇开始研究SpringMVC的使用!SpringMVC数据响应和获取请求数据

SpringMVC的数据响应方式 页面跳转 直接返回字符串通过ModelAndView对象返回 回写数据 直接返回字符串返回对象或集合 页面跳转&#xff1a; 返回字符串方式 直接返回字符串&#xff1a;此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转 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参数解释 &#x1f433; dock…

【SSM-SSM整合】将Spring、SpringMVC、Mybatis三者进行整合;本文阐述了几个核心原理知识点,附带对应的源码以及描述解析

SSM整合的基础jar包 需要创建的层级&#xff1a; controller层 该层下需要创建对应的控制器Servlet POJO文件夹 该层下需要创建与数据库对应的POJO类 mapper层 该层下需要创建Mapper的接口实现 service层 该层下需要创建业务层的接口及其接口实现 需要创建的配置文件&#x…

MYSQL数据库集群高可用和数据监控平台

项目环境 项目拓扑结构 软硬件环境清单 软硬件环境清单 软硬件环境清单 主机名IP硬件软件 master1 192.168.12.130 VIP&#xff1a;192.168.12.200 cpu:1颗2核 内 存&#xff1a;2GB HDD&#xff1a;20GB 网 络&#xff1a;NAT VmWare17 OpenEuler22.03 SP4 MySql8.0.3…

uni-app vue3版本打包h5后 页面跳转报错(uni[e] is not a function)

先看问题 解决方案 在HBuilderX项目中&#xff0c;若需在Web配置中显式关闭摇树优化&#xff08;Tree Shaking&#xff09;&#xff0c;可以通过以下步骤实现&#xff1a;首先&#xff0c;在配置中打开摇树优化&#xff0c;然后再将其关闭。这样操作后&#xff0c;配置文件中会…

【Redis】缓存穿透、缓存雪崩、缓存击穿

1.缓存穿透 是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;导致请求直接穿透缓存到达数据库&#xff0c;给数据库带来压力的情况。 常见的解决方案有两种&#xff1a; 缓存空对象&#xff1a;实现简单&#xff0c;维护方便&am…

告别数据僵尸!Redis实现自动清理过期键值对

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

web第三次课后作业--基于JDBC对mysql数据库的增删查改操作

一、工程搭建步骤 1.新建java项目&#xff0c;添加jdbc依赖 2.写java程序 3.添加mysql数据源&#xff0c;连接本地数据库 4.运行程序二、运行结果 三、代码 代码解析 加载数据驱动 try {Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundExceptio…

[数据结构]5. 栈-Stack

栈-Stack 1. 介绍2. 栈的实现2.1 基于链表的实现2.2 基于数组的实现 3. 栈操作CreateInitilizateDestoryPushPopTopEmptySize 1. 介绍 栈&#xff08;stack&#xff09; 是一种遵循先入后出逻辑的线性数据结构。顶部称为“栈顶”&#xff0c;底部称为“栈底”。把元素添加到栈…

基于Spring Boot + Vue的高校心理教育辅导系统

一、项目背景介绍 随着高校对学生心理健康教育的重视&#xff0c;传统的人工心理辅导与测评模式已经难以满足广大师生的个性化需求。为了提高心理服务的效率、便捷度和覆盖范围&#xff0c;本项目开发了一个高校心理教育辅导系统&#xff0c;集成心理评测、辅导预约、留言交流…

JavaSwing之-JDialog

JavaSwing之-JDialog JDialog 是 Java Swing 中用于创建对话框窗口的容器类&#xff0c;继承自 Dialog 类&#xff08;AWT&#xff09;&#xff0c;常用于显示临时信息、获取用户输入或执行模态操作。它是 javax.swing.JDialog 包中的类。 与 JFrame 不同的是&#xff0c;JDia…

【学习路线】 游戏客户端开发入门到进阶

目录 游戏客户端开发入门到进阶&#xff1a;系统学习路线与推荐书单一、学习总原则&#xff1a;从底层出发&#xff0c;项目驱动&#xff0c;持续迭代二、推荐学习路线图&#xff08;初学者→进阶&#xff09;第一阶段&#xff1a;语言基础与编程思维第二阶段&#xff1a;游戏开…

部署安装gitlab-ce-17.9.7-ce.0.el8.x86_64.rpm

目录 ​编辑 实验环境 所需软件 实验开始 安装部署gitlab171.配置清华源仓库&#xff08;版本高的系统无需做&#xff09;vim /etc/yum.repos.d/gitlab-ce.repo 2.提前下载包dnf localinstall gitlab-ce-17.9.7-ce.0.el8.x86_64.rpm --rocklinux 3.修改配…