1. 程式人生 > 其它 >SignalR循序漸進(一)簡單的聊天程式

SignalR循序漸進(一)簡單的聊天程式

前陣子把玩了一下SignalR,起初以為只是個real-time的web通訊元件。研究了幾天後發現,這玩意簡直屌炸天,它完全就是個.net的雙向非同步通訊框架,用它能做很多不可思議的東西。它基於Owin,可以脫離繁重的System.Web,隨意寄宿在IIS,WindowsService,或者一個控制檯程式,這樣它即能用於b/s的Web應用,也能用在客戶端程式或者服務之間的通訊上。對它的介紹網上早已鋪天蓋地,這而就不再囉嗦了,先來個小例子,一個聊天室程式。

服務端


新建一個叫SignalRDemo的工程,注意一定要選擇.net Framework4.5及以上。

為了讓服務端可以自寄宿,安裝signalr self host元件。

public class ChatHub : Hub
    {
        public void Send(string name, string message)
        {
            Console.WriteLine("ConnectionId:{0}, InvokeMethod:{1}", Context.ConnectionId, "Send");
            Clients.AllExcept(Context.ConnectionId).broadcast(name, message);
        }
    }

新建一個ChatHub,建立一個行為叫Send,裡面包含了一條控制檯呼叫記錄以及讓所有除了發起者外的連結Hub的客戶端執行客戶端方法broadcast。

[assembly: OwinStartup(typeof(Host.Startup))]

namespace Host
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

建立一個啟動類,將所有的Hub對映。

class Program
    {
        static void Main(string[] args)
        {
            var url = "localhost:10086";
            WebApp.Start<Startup>(url);
            Console.WriteLine("Server started,url is {0}", url);
            Console.ReadLine();
        }
    }

在Main中寫上url和埠,直接用WebApp啟動。

控制檯啟動後的輸出。

用瀏覽器訪問

好了,到這兒服務端程式碼就全部完成了。接下來建立客戶端來呼叫。客戶端暫時不採用website,同樣用控制檯程式來承載。

客戶端


建立一個Client的控制檯工程,新增SignalR的Client包。

var url = "http://localhost:10086/";
            var connection = new HubConnection(url);
            var chatHub = connection.CreateHubProxy("ChatHub");
            connection.Start().ContinueWith(t =>
            {
                if (t.IsFaulted)
                {
                    Console.WriteLine("Connection fault.");
                }
            });

在客戶端的Main中建立一個HubConnection,建立ChatHub的代理,通過connection.Start啟動連線。

var broadcastHandler = chatHub.On<string, string>("broadcast", (name, message) =>
            {
                Console.WriteLine("[{0}]{1}: {2}", DateTime.Now.ToString("HH:mm:ss"), name, message);
            });

定義客戶端方法,之前在服務端用Clients.All.broadcast的就是在這邊定義的方法。

Console.WriteLine("Please input your name:");
            var _name = Console.ReadLine();
            Console.WriteLine("Start chat!");
            while (true)
            {
                var _message = Console.ReadLine();
                chatHub.Invoke("Send", _name, _message).ContinueWith(t => {
                    if (t.IsFaulted)
                    {
                        Console.WriteLine("Connection error!");
                    }
                });
            }

最後,寫上一個簡單的聊天邏輯。當輸入名字後,在while的迴圈內,每輸入一行文字,hub就呼叫服務端的Send方法。同時服務端在執行Send的過程後又會回掉客戶端方法。這種通訊方式在以前的C#程式碼中是很不可思議的,因為同樣的客戶端方法還可以寫在js裡!

 

執行效果


執行效果如圖。

好了,一個基於SignalR的簡單的控制檯聊天程式就完成了,強大的SignalR讓開發者不需要關心Socket的一堆煩人的問題。

 

問題


上面的那個聊天程式看似很方便很強大,但似乎哪兒有一些奇怪?

比如說,服務端呼叫客戶端的方法用的是dynamic的,客戶端呼叫服務端的方法傳入的都是string型別的,這樣首先就不具備擴充套件性和進行一些規則約束。

  1. 能不能讓客戶端宣告一個強型別的方法列表呢?這樣首先不容易寫錯。
  2. 同樣的,能不能讓服務端宣告一個強型別的方法列表給客戶端呼叫呢?

下一篇將對上面的2個問題進行思考,並給出解決方案。

 

前陣子把玩了一下SignalR,起初以為只是個real-time的web通訊元件。研究了幾天後發現,這玩意簡直屌炸天,它完全就是個.net的雙向非同步通訊框架,用它能做很多不可思議的東西。它基於Owin,可以脫離繁重的System.Web,隨意寄宿在IIS,WindowsService,或者一個控制檯程式,這樣它即能用於b/s的Web應用,也能用在客戶端程式或者服務之間的通訊上。對它的介紹網上早已鋪天蓋地,這而就不再囉嗦了,先來個小例子,一個聊天室程式。

服務端


新建一個叫SignalRDemo的工程,注意一定要選擇.net Framework4.5及以上。

為了讓服務端可以自寄宿,安裝signalr self host元件。

public class ChatHub : Hub
    {
        public void Send(string name, string message)
        {
            Console.WriteLine("ConnectionId:{0}, InvokeMethod:{1}", Context.ConnectionId, "Send");
            Clients.AllExcept(Context.ConnectionId).broadcast(name, message);
        }
    }

新建一個ChatHub,建立一個行為叫Send,裡面包含了一條控制檯呼叫記錄以及讓所有除了發起者外的連結Hub的客戶端執行客戶端方法broadcast。

[assembly: OwinStartup(typeof(Host.Startup))]

namespace Host
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

建立一個啟動類,將所有的Hub對映。

class Program
    {
        static void Main(string[] args)
        {
            var url = "localhost:10086";
            WebApp.Start<Startup>(url);
            Console.WriteLine("Server started,url is {0}", url);
            Console.ReadLine();
        }
    }

在Main中寫上url和埠,直接用WebApp啟動。

控制檯啟動後的輸出。

用瀏覽器訪問

好了,到這兒服務端程式碼就全部完成了。接下來建立客戶端來呼叫。客戶端暫時不採用website,同樣用控制檯程式來承載。

客戶端


建立一個Client的控制檯工程,新增SignalR的Client包。

var url = "http://localhost:10086/";
            var connection = new HubConnection(url);
            var chatHub = connection.CreateHubProxy("ChatHub");
            connection.Start().ContinueWith(t =>
            {
                if (t.IsFaulted)
                {
                    Console.WriteLine("Connection fault.");
                }
            });

在客戶端的Main中建立一個HubConnection,建立ChatHub的代理,通過connection.Start啟動連線。

var broadcastHandler = chatHub.On<string, string>("broadcast", (name, message) =>
            {
                Console.WriteLine("[{0}]{1}: {2}", DateTime.Now.ToString("HH:mm:ss"), name, message);
            });

定義客戶端方法,之前在服務端用Clients.All.broadcast的就是在這邊定義的方法。

Console.WriteLine("Please input your name:");
            var _name = Console.ReadLine();
            Console.WriteLine("Start chat!");
            while (true)
            {
                var _message = Console.ReadLine();
                chatHub.Invoke("Send", _name, _message).ContinueWith(t => {
                    if (t.IsFaulted)
                    {
                        Console.WriteLine("Connection error!");
                    }
                });
            }

最後,寫上一個簡單的聊天邏輯。當輸入名字後,在while的迴圈內,每輸入一行文字,hub就呼叫服務端的Send方法。同時服務端在執行Send的過程後又會回掉客戶端方法。這種通訊方式在以前的C#程式碼中是很不可思議的,因為同樣的客戶端方法還可以寫在js裡!

 

執行效果


執行效果如圖。

好了,一個基於SignalR的簡單的控制檯聊天程式就完成了,強大的SignalR讓開發者不需要關心Socket的一堆煩人的問題。

 

問題


上面的那個聊天程式看似很方便很強大,但似乎哪兒有一些奇怪?

比如說,服務端呼叫客戶端的方法用的是dynamic的,客戶端呼叫服務端的方法傳入的都是string型別的,這樣首先就不具備擴充套件性和進行一些規則約束。

  1. 能不能讓客戶端宣告一個強型別的方法列表呢?這樣首先不容易寫錯。
  2. 同樣的,能不能讓服務端宣告一個強型別的方法列表給客戶端呼叫呢?

下一篇將對上面的2個問題進行思考,並給出解決方案。