跨外網接收雲服務器發來的消息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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章