標籤:winform style blog class code java
上一篇文章,我們瞭解了用戶端如何與伺服器建立WebSocket串連。但是一個巴掌拍不響,既然是通訊,就必然最少要有兩個端。今天我們來看看c#如何用已有的架構實現一個WebSocket服務端。
在.Net Framework 4.5及以上版本中,微軟為我們整合了WebSocket協議的基本實現。微軟提供的WebSocket對象位於System.Net.WebSocket命名空間下,使用起來挺繁瑣的,所以我選擇了SuperWebSocket架構來簡化開發的難度。
SuperWebSocket架構可以通過NuGet直接擷取並引用到項目中,也可以在http://superwebsocket.codeplex.com/中下載最新的DLL
我們來看SuperWebSocket如何我們快速搭建一個服務端
WebSocketServer wsServer = new WebSocketServer(); if (!wsServer.Setup("127.0.0.1", 2012)) { //設定IP 與 連接埠失敗 通常是IP 和連接埠範圍不對引起的 IPV4 IPV6 } if (!wsServer.Start()) { //開啟服務失敗 基本上是連接埠被佔用或者被 某殺毒軟體攔截造成的 return; } wsServer.NewSessionConnected += (session) => { //有新的串連 }; wsServer.SessionClosed += (session, reason) => { //有斷開的串連 }; wsServer.NewMessageReceived += (session, message) => { //接收到新的簡訊 }; wsServer.NewDataReceived += (session, bytes) => { //接收到新的二進位訊息 }; Console.ReadKey(); wsServer.Stop();View Code
這裡WebSocketServer對象通過Setup方式對要偵聽的IP及連接埠進行了設定。然後使用Start方法啟動偵聽。
Setup方法有4種重載,但是我們通常用到的只有設定IP和連接埠,IP為string類型,如果傳入的字串無法被轉換為支援的IP格式,Setup方法會返回false表示設定失敗。
WebSocketServer還提供了4個事件用以管理與用戶端的串連、斷開、和接受訊息動作。新版本的WebSocket支援傳送的資料格式有 “文本” 和 “二進位”兩種,NewMessageReceived事件用於處理文本類型的訊息,NewDataReceived事件用於處理二進位類型的訊息。
到這裡 我們已經成功的搭建了一個實現了WebSocket協議的服務端了。至於服務端的寄宿方式有很多,SuperWebSocket架構支援以 控制台、Winform、IIS以及Windows服務的形式寄宿服務,不過網上很多資料都不建議在IIS中寄宿服務,據說是因為寄宿在IIS中效能比較低。
WebSocket既然是雙工通訊,那麼我們就不能光等著接收來自用戶端的訊息, 我們也需要從服務端向用戶端“推送”訊息,現在我們來看如何由服務端向用戶端發送訊息。
SuperWebSocket架構中,服務端與用戶端建立的連線物件為WebSocketSession類型,也就是說它將每一個用戶端的執行個體視為一個會話,在用戶端建立串連的時候,產生這個會話,在用戶端中斷連線的時候,銷毀這個會話,而用戶端與服務端進行訊息通訊的時候,也依賴這個會話進行傳遞。我們要實現伺服器端向用戶端的廣播,就要擷取到當前正在活動的所有會話,我們通過代碼來看如何擷取所有的會話
wsServer.GetAllSessions() //擷取所有的會話 已斷開的會話不會出現在集合中
很簡單吧,在擷取到活動的會話之後 我們就可以向用戶端發送訊息了,這裡我們讓伺服器向用戶端定時發送伺服器時間
Timer timer = new Timer((data) => { var msg = string.Format("伺服器目前時間:{0:HH:MM:ss}", DateTime.Now); //對當前已串連的所有會話進行廣播 foreach (var session in wsServer.GetAllSessions()) { session.Send(msg); } }, null, 1000, 1000);
這樣 所有與服務端保持串連的用戶端就都可以接受到來自伺服器端的訊息了。
在這個例子裡 我們看到了所有的訊息都是由會話對象發出的,會話對象Send的訊息 也支援“文本”與“二進位兩種形式,同時會話對象還提供一個SendCloseHandshakeResponse()方法向用戶端發送一個強制中斷連線的指令。
WebSocketSession對象包含了服務端和用戶端的所有資訊,以及WebSocketServer對象本身,我們可以利用它做很多事情,下邊我們就來實現一個簡單的聊天室。至於聊天室的原理 就是一個人將要說的話發送到伺服器,再由伺服器廣播給在這個聊天室裡的所有人看到。恩 就這麼簡單。我們來上代碼,多了不解釋,相當簡單。
public class ChatWebSocket { private const string ip = "127.0.0.1"; private const int port = 2014; private WebSocketServer ws = null;//SuperWebSocket中的WebSocketServer對象 public ChatWebSocket() { ws = new WebSocketServer();//執行個體化WebSocketServer //添加事件偵聽 ws.NewSessionConnected += ws_NewSessionConnected;//有新會話握手並串連成功 ws.SessionClosed += ws_SessionClosed;//有會話被關閉 可能是服務端關閉 也可能是用戶端關閉 ws.NewMessageReceived += ws_NewMessageReceived;//有用戶端發送新的訊息 } void ws_NewSessionConnected(WebSocketSession session) { Console.WriteLine("{0:HH:MM:ss} 與用戶端:{1}建立新會話", DateTime.Now, GetSessionName(session)); var msg = string.Format("{0:HH:MM:ss} {1} 進入聊天室", DateTime.Now, GetSessionName(session)); SendToAll(session, msg); } void ws_SessionClosed(WebSocketSession session, SuperSocket.SocketBase.CloseReason value) { Console.WriteLine("{0:HH:MM:ss} 與用戶端:{1}的會話被關閉 原因:{2}", DateTime.Now, GetSessionName(session), value); var msg = string.Format("{0:HH:MM:ss} {1} 離開聊天室", DateTime.Now, GetSessionName(session)); SendToAll(session, msg); } void ws_NewMessageReceived(WebSocketSession session, string value) { var msg = string.Format("{0:HH:MM:ss} {1}說: {2}", DateTime.Now, GetSessionName(session), value); SendToAll(session, msg); } /// <summary> /// 啟動服務 /// </summary> /// <returns></returns> public void Start() { if (!ws.Setup(ip, port)) { Console.WriteLine("ChatWebSocket 設定WebSocket服務偵聽地址失敗"); return; } if (!ws.Start()) { Console.WriteLine("ChatWebSocket 啟動WebSocket服務偵聽失敗"); return; } Console.WriteLine("ChatWebSocket 啟動服務成功"); } /// <summary> /// 停止偵聽服務 /// </summary> public void Stop() { if (ws != null) { ws.Stop(); } } private string GetSessionName(WebSocketSession session) { //這裡用Path來取Name 不太科學…… return HttpUtility.UrlDecode(session.Path.TrimStart(‘/‘)); } private void SendToAll(WebSocketSession session, string msg) { //廣播 foreach (var sendSession in session.AppServer.GetAllSessions()) { sendSession.Send(msg); } } }View Code
關與SuperWebSocket的基本使用就介紹到這裡了……頂著老闆不時窺屏的壓力,可能文章有點語無倫次,希望大家多多體諒,也希望大家提出寶貴意見 共同學習。下一篇我會考慮介紹“子協議”和SuperWebSocket提供的Json字串類型資料的處理
範例程式碼在這裡 下載