天天看點

SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連

一、前言

SignalR是微軟推出的開源實時通信架構。其内部使用Web Socket, Server Sent Events 和 Long Polling作為底層傳輸方式,SignalR會根據用戶端和服務端的支援情況,采用回落機制來選擇一種傳輸方式,Web Socket是首選的。在web開發中,SignalR可以很好的解決傳統ajax輪詢的問題,真正做到實時通信。

二、編碼

  • 首先建立2個項目,一個控制台項目,一個web項目。控制台項目作為SignalR服務端,web項目作為用戶端。
    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連
  • 先從服務端開始:

    安裝NuGet包

    控制台程式作為宿主實作自托管,需要安裝:

    Microsoft.AspNet.SignalR.SelfHost

    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連
    添加跨域支援:

    Microsoft.Owin.Cors

    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連
  • 服務端SignalRServer.Program代碼:
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace SignalRServer
{
    class Program
    {
        static void Main(string[] args)
        {
            var url = "http://localhost:8019";
            using (WebApp.Start(url))
            {
                Console.WriteLine("SignalR運作:" + url);
                Console.WriteLine("輸入要發送的消息,使用者與消息之間用空格隔開:");

                var hub = GlobalHost.ConnectionManager.GetHubContext<CustomHub>();

                while (true)
                {
                    var str = Console.ReadLine();
                    hub.Clients.Client(CustomHub.OnLineUsers[str.Split(' ')[0]]).refreshData(str.Split(' ')[1]);
                }
            }
        }
    }

    public class CustomHub : Hub
    {
        //線上使用者
        public static ConcurrentDictionary<string, string> OnLineUsers = new ConcurrentDictionary<string, string>();

        public override Task OnConnected()
        {
            string clientName = Context.QueryString["clientName"].ToString();
            OnLineUsers.AddOrUpdate(clientName, Context.ConnectionId, (key, value) =>
            {
                return Context.ConnectionId;
            });
            Console.WriteLine($"{clientName}:{Context.ConnectionId}已連接配接。");
            return base.OnConnected();
        }

        public override Task OnDisconnected(bool stopCalled)
        {
            string clientName = Context.QueryString["clientName"].ToString();
            string client;
            OnLineUsers.TryRemove(clientName, out client);
            Console.WriteLine($"{clientName}:{Context.ConnectionId}已斷開。");
            return base.OnDisconnected(stopCalled);
        }

        public override Task OnReconnected()
        {
            string clientName = Context.QueryString["clientName"].ToString();
            OnLineUsers.AddOrUpdate(clientName, Context.ConnectionId, (key, value) =>
            {
                return Context.ConnectionId;
            });
            Console.WriteLine($"{clientName}:{Context.ConnectionId}已重連。");
            return base.OnReconnected();
        }
    }

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(CorsOptions.AllowAll);
            app.MapSignalR();
        }
    }

}
           

以上代碼大緻就是指定一個url啟動SignalR服務,CustomHub中維護了一個線上用戶端集合,控制台根據輸入的資訊發送到對應的用戶端...

  • 下面是用戶端

    同樣先安裝NuGet包

    安裝

    Microsoft.AspNet.SignalR.JS

    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連
  • 建立2個視圖User1,User2,用來代表2個不同使用者

    User1.cshtml代碼,支援斷線重連:

@{
    ViewBag.Title = "Index";
    Layout = null;
}

<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script id="signalr_script" src="http://localhost:8019/signalr/hubs"></script>

<script type="text/javascript">
    $(function () {
        //連接配接Signalr伺服器
        signalrInit();
    });

    //signalr初始化配置
    function signalrInit() {
        try {
            //Set the hubs URL for the connection
            $.connection.hub.url = 'http://localhost:8019/signalr';
            $.connection.hub.qs = { "clientName": "user1" };

            // Declare a proxy to reference the hub.
            var chat = $.connection.customHub;

            // Create a function that the hub can call to broadcast messages.
            chat.client.refreshData = function (message) {
                //TODO:收到服務端資料
                appendMessage(message);
            };

            signalrConnection();

            $.connection.hub.disconnected(function () {
                appendMessage('SignalR連接配接斷開!');
                //重連
                setTimeout(signalrConnection, 10000);
            });
            //$.connection.hub.stateChanged(function (change) { console.log(change); });
        } catch (e) {
            appendMessage("SignalR連接配接異常" + e);
            //重新加載hubs
            $.getScript('http://localhost:8019/signalr/hubs');
            //重新初始化 斷線重連
            setTimeout(signalrInit, 10000);
        }
    }

    //signalr連接配接
    function signalrConnection() {
        $.connection.hub.start()
                .done(function () { appendMessage('SignalR建立連接配接成功'); })
                .fail(function () { appendMessage('SignalR建立連接配接失敗'); });
    }

    function appendMessage(message) {
        $("#box").append("<p>" + message + "</p>");
    }
</script>

<h1>User1</h1>
<div id="box">

</div>
           

User2.cshtml代碼:

@{
    ViewBag.Title = "Index";
    Layout = null;
}

<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script id="signalr_script" src="http://localhost:8019/signalr/hubs"></script>

<script type="text/javascript">
    $(function () {
        //連接配接Signalr伺服器
        signalrInit();
    });

    //signalr初始化配置
    function signalrInit() {
        try {
            //Set the hubs URL for the connection
            $.connection.hub.url = 'http://localhost:8019/signalr';
            $.connection.hub.qs = { "clientName": "user2" };

            // Declare a proxy to reference the hub.
            var chat = $.connection.customHub;

            // Create a function that the hub can call to broadcast messages.
            chat.client.refreshData = function (message) {
                //TODO:收到服務端資料
                appendMessage(message);
            };

            signalrConnection();

            $.connection.hub.disconnected(function () {
                appendMessage('SignalR連接配接斷開!');
                //重連
                setTimeout(signalrConnection, 10000);
            });
            //$.connection.hub.stateChanged(function (change) { console.log(change); });
        } catch (e) {
            appendMessage("SignalR連接配接異常" + e);
            //重新加載hubs
            $.getScript('http://localhost:8019/signalr/hubs');
            //重新初始化 斷線重連
            setTimeout(signalrInit, 10000);
        }
    }

    //signalr連接配接
    function signalrConnection() {
        $.connection.hub.start()
                .done(function () { appendMessage('SignalR建立連接配接成功'); })
                .fail(function () { appendMessage('SignalR建立連接配接失敗'); });
    }

    function appendMessage(message) {
        $("#box").append("<p>" + message + "</p>");
    }
</script>

<h1>User2</h1>
<div id="box">

</div>
           

三、效果

  • 服務端和用戶端的代碼已完成,現在先運作一下服務端控制台程式。右鍵編譯好的SignalRServer.exe,以管理者身份運作(最好是管理者身份運作,不然可能會報錯)。
    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連
  • 運作用戶端,浏覽器分别打開User1,User2頁面
    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連
    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連
    用戶端已經顯示連接配接成功
    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連
    服務端也顯示2個已連接配接
  • 向User1發送消息:
    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連
  • 向User2發送消息:
    SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連

四、總結

以上就是SignalR的基本使用。

有一些可能的坑:

1.服務端控制台啟動報錯:嘗試用管理者身份啟動

2.服務端啟動正常,用戶端卻無法連接配接,報錯Cannot read property 'client' of undefined:有時候可能是端口的問題,換一個端口試一下

3.程式放到伺服器,通過外網IP無法連接配接:WebApp.Start()嘗試使用*号格式:http://*:8019

——本文使用【Typora】+【EasyBlogImageForTypora】編輯

歡迎關注我的公衆号,一起學習。

如果本文對您有所幫助,您可以點選右下方的【推薦】按鈕支援一下;文中如有不妥之處,還望指正,非常感謝!!!

SignalR控制台自托管服務端向web用戶端指定使用者推送資料,用戶端斷線重連

作者:xhznl

出處:http://www.cnblogs.com/xhznl/

文章可以轉載,但請注明出處

繼續閱讀