上一篇文章,我們了解了客戶端如何與服務器創建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();
這里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); } } }
關與SuperWebSocket的基本使用就介紹到這里了……頂着老板不時窺屏的壓力,可能文章有點語無倫次,希望大家多多體諒,也希望大家提出寶貴意見 共同學習。下一篇我會考慮介紹“子協議”和SuperWebSocket提供的Json字符串類型數據的處理
示例代碼在這里 下載
提示:
SuperSocket與SuperWebSocket框架都是Kerry Jiang的項目 SuperSocket最新版本號是1.6 SuperWebSocket最新版本號是0.8 之前一直以為第一個是官網的……后來查了下資料不是……第一個框架BUG海多……這里給大家提個醒……
本系列本月暫停更新………這個框架資料很少……而且有點坑……在死磕探路中……