跨外网接收云服务器发来的消息ASP.NET SignalR

SignalR

ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程。实时 Web 功能是指这样一种功能:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。

服务端:控制台应用程序----可以看到客户端连接掉线的消息,给那个客户端发送了消息

客户端:windows服务---通过命令注册到windows服务里开机自动启动用到Topshelf、定时调度Quartz,同时客户端又是一个服务端来给UDP客户端发送消息。

本来想实现Quartz的job调度,但是这样注入不到windows服务里,最后还是选择了用 System.Timers.Timer

客户端实现如下:

1、新建控制台程序起名叫SignalRClient

2、引入如下nuget包

Microsoft.AspNet.SignalR.Client
log4net
Quartz
Topshelf

3、普通的控制台程序是无法注入到windows服务里,必须用Topshelfc才可以注入到windows服务里,并且可以启动停止。

注入的命令很简单打开dos命令

命令

4、客户端代码如下:

新建TopshelfService类

using Microsoft.AspNet.SignalR.Client;
using SignalRClient.Entity;
using System;
using System.Configuration;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace SignalRClient
{
    public class TopshelfService
    {
        private static Socket udpServer;
        private static string _message = "";
        static HubConnection connection = null;
        static IHubProxy myHub = null;
        static string url = ConfigurationManager.AppSettings.Get("url");
        public void Start()
        {
            //服务逻辑
            try
            {
                double time = double.Parse(ConfigurationManager.AppSettings["timeout"]);
                System.Timers.Timer t = new System.Timers.Timer(time);//实例化Timer类,设置间隔时间为10000毫秒;

                t.Elapsed += new System.Timers.ElapsedEventHandler(theout);//到达时间的时候执行事件;

                t.AutoReset = true;//设置是执行一次(false)还是一直执行(true);

                t.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件;
                t.Start();

                //以下是有开启了一个socket当作服务端给本地socket发送消息
                udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                //udpServer.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6678));//绑定端口号和IP
                Console.WriteLine("socket服务端开启成功!");
                //Thread t1 = new Thread(ReciveMsg);//开启接收消息线程
                //t1.Start();
                Thread t2 = new Thread(sendMsg);//开启发送消息线程
                t2.Start();

                Console.ReadKey();
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(ex.Message.ToString(), ex);
            }
        }

        public void Stop()
        {

        }

        private static void theout(object source, System.Timers.ElapsedEventArgs e)
        {
            NewMethod();
        }

        /// <summary>
        /// UDP服务端向特定ip的主机的端口发送数据报
        /// </summary>
        static void sendMsg()
        {
            EndPoint point = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6677);
            while (true)
            {
                string msg = CommonMsg.Message;
                if (!string.IsNullOrWhiteSpace(msg))
                {
                    udpServer.SendTo(Encoding.UTF8.GetBytes(msg), point);
                    //_message = "";
                }

            }
        }
        /// <summary>
        /// 一直等待服务端推送消息
        /// </summary>
        private static void NewMethod()
        {
            string clientName = ConfigurationManager.AppSettings.Get("clientName");
            Console.WriteLine("客户端: " + "设备id =》" + clientName + "开启");
            connection = new HubConnection(url, "clientName=" + clientName);
            //类名必须与服务端一致
            myHub = connection.CreateHubProxy("BroadcastHub");

            //方法名必须与服务端一致
            myHub.On<string>("ReceiveMsg", ReceiveMsg);
            connection.Start().ContinueWith(task =>
            {
                if (!task.IsFaulted)
                {
                    Console.WriteLine("与服务器连接成功");
                }
                else
                {
                    Console.WriteLine("与服务器连接失败,请确认服务器是否开启!");
                }
            }).Wait();
        }

        /// <summary>
        /// 从服务端接收到的消息
        /// </summary>
        /// <param name="message"></param>
        private static void ReceiveMsg(string message)
        {
            CommonMsg.Message = message;
            Console.WriteLine("来自服务器的消息:" + message);
        }

        /// <summary>
        /// 接收发送给本机ip对应端口号的数据报
        /// </summary>
        static void ReciveMsg()
        {
            while (true)
            {
                EndPoint point = new IPEndPoint(IPAddress.Any, 0);//用来保存发送方的ip和端口号
                byte[] buffer = new byte[1024];
                int length = udpServer.ReceiveFrom(buffer, ref point);//接收数据报
                string message = Encoding.UTF8.GetString(buffer, 0, length);
                Console.WriteLine(point.ToString() + message);

            }
        }

    }
}

新建一个公共接收消息类CommonMsg

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SignalRClient.Entity
{
    public class CommonMsg
    {
        public static string Message = "";
    }
}

新建一个日志帮助类LogHelper

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SignalRClient
{
    public class LogHelper
    {
        public static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("loginfo");
        public static readonly log4net.ILog logerror = log4net.LogManager.GetLogger("logerror");
        public static void WriteLog(string info)
        {
            if (loginfo.IsInfoEnabled)
            {
                loginfo.Info(info);
            }
        }

        public static void WriteLog(string info, Exception ex)
        {
            if (logerror.IsErrorEnabled)
            {
                logerror.Error(info, ex);
            }
        }
    }
}

新建一个日志config文件

<?xml version="1.0" encoding="utf-8"?>
<log4net>
  <!--错误日志类-->
  <logger name="logerror">
    <!--日志类的名字-->
    <level value="ALL" />
    <!--定义记录的日志级别-->
    <appender-ref ref="ErrorAppender" />
    <!--记录到哪个介质中去-->
  </logger>
  <!--信息日志类-->
  <logger name="loginfo">
    <level value="ALL" />
    <appender-ref ref="InfoAppender" />
  </logger>
  <!--错误日志附加介质-->
  <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
    <!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
    <param name="File" value="D:\\Log\\SinalRClinetLog\\" />
    <!--日志输出到exe程序这个相对目录下-->
    <param name="AppendToFile" value="true" />
    <!--输出的日志不会覆盖以前的信息-->
    <param name="MaxSizeRollBackups" value="100" />
    <!--备份文件的个数-->
    <param name="MaxFileSize" value="10240" />
    <!--当个日志文件的最大大小-->
    <param name="StaticLogFileName" value="false" />
    <!--是否使用静态文件名-->
    <param name="DatePattern" value="yyyyMMdd&quot;.htm&quot;" />
    <!--日志文件名-->
    <param name="RollingStyle" value="Date" />
    <!--文件创建的方式,这里是以Date方式创建-->
    <!--错误日志布局-->
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="&lt;HR COLOR=red&gt;%n异常时间:%d [%t] &lt;BR&gt;%n异常级别:%-5p &lt;BR&gt;%n异 常 类:%c [%x] &lt;BR&gt;%n%m &lt;BR&gt;%n &lt;HR Size=1&gt;"  />
    </layout>
  </appender>
  <!--信息日志附加介质-->
  <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
    <param name="File" value="Log\\LogInfo\\" />
    <param name="AppendToFile" value="true" />
    <param name="MaxFileSize" value="10240" />
    <param name="MaxSizeRollBackups" value="100" />
    <param name="StaticLogFileName" value="false" />
    <param name="DatePattern" value="yyyyMMdd&quot;.htm&quot;" />
    <param name="RollingStyle" value="Date" />
    <!--信息日志布局-->
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="&lt;HR COLOR=blue&gt;%n日志时间:%d [%t] &lt;BR&gt;%n日志级别:%-5p &lt;BR&gt;%n日 志 类:%c [%x] &lt;BR&gt;%n%m &lt;BR&gt;%n &lt;HR Size=1&gt;"  />
    </layout>
  </appender>
</log4net>

新建修改app.config文件

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="MySection" type="SignalRClient.ConfigSectionHandler, SignalRClient" />
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <appSettings>
    <!--每个设备的id-->
    <add key="clientName" value="69" />
    <!--服务器地址-->
    <add key="url" value="http://IP:5000" />
    <!--每1分钟重启一次客户端-->
    <add key="timeout" value="60000" />
    <add key="timeoutS" value="0/60 * * * * ?" />
    <add key="ClientSettingsProvider.ServiceUri" value="" />
  </appSettings>
  <system.web>
    <membership defaultProvider="ClientAuthenticationMembershipProvider">
      <providers>
        <add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
      </providers>
    </membership>
    <roleManager defaultProvider="ClientRoleProvider" enabled="true">
      <providers>
        <add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
      </providers>
    </roleManager>
  </system.web>
</configuration>

修改应用程序主入口

using Microsoft.AspNet.SignalR.Client;
using SignalRClient.Entity;
using System.ComponentModel;
using System.Configuration;
using System.Net.Sockets;
using Topshelf;

namespace SignalRClient
{
    public class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(c =>
            {        
                c.Service<TopshelfService>(s =>
                {
                    s.ConstructUsing(b => new TopshelfService());
                    s.WhenStarted(o => o.Start());
                    s.WhenStopped(o => o.Stop());
                });
                c.RunAsLocalSystem();
                c.StartAutomatically();
                c.SetServiceName("SignalRClientServices");
                c.SetDisplayName("SignalRClientServices");
                c.SetDescription("SignalRClientServices");
            });
        }
    }
}

大功告成

服务端源码地址:https://download.csdn.net/download/it_ziliang/11250515

客户端源码地址:https://download.csdn.net/download/it_ziliang/11250526

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值