关于推送后台的webapi demo



前言

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瓜皮弟子头很铁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值