本文將使用一個Nuget公開的組件技術來實現一對多的數據通訊功能,提供了一些簡單的API,來方便的向服務器進行數據請求。html
在visual studio 中的Nuget管理器中能夠下載安裝,也能夠直接在Nuget控制檯輸入下面的指令安裝:git
Install-Package HslCommunication
Nuget安裝教程 http://www.cnblogs.com/dathlin/p/7705014.htmlgithub
聯繫做者及加羣方式(激活碼在羣裏發放):http://www.hslcommunication.cn/Cooperation數組
一個用於同步數據交互的網絡通訊類,在實際的程序開發中,咱們常常會碰到這樣的須要,咱們須要向服務器請求一些數據,而後接收從服務器返回的數據,數據類型一般爲 byte[] 或是 string ,類型,因此一般在服務器端會配置一個數據處理總站,每次請求都會帶有一個信號頭,用於服務器區分不一樣的信息機制,而咱們可使用組件中的 NetSimplifyServer 和 NetSimplifyClient 類來完成功能。安全
該通信類對全部的底層進行了封裝,包含了協議頭定義,令牌驗證,數據的加密解密,壓縮和解壓縮,能夠安全的在局域網和廣域網上進行數據傳播,服務器端還增長了防止惡意鏈接機制,有效抵制來自網絡的惡意網絡攻擊。服務器
日誌組件全部的功能類都在 HslCommunication 和 HslCommunication.Enthernet 命名空間,因此再使用以前先添加網絡
using HslCommunication; using HslCommunication.Enthernet;
咱們先要在服務器端進行建立網絡監聽,這樣才能讓客戶端鏈接到服務器,服務器須要先實例化及初始化代碼以下,代碼直接在服務器主窗口下面:架構
// 用戶同步數據傳送的引擎 private NetSimplifyServer net_simplify_server = new NetSimplifyServer(); //實例化 // 同步傳送數據的初始化 private void Net_Simplify_Server_Initialization() { try { net_simplify_server.KeyToken = Guid.Empty;//設置身份令牌,本質就是一個GUID碼,驗證客戶端使用 net_simplify_server.LogNet = new LogNetSingle(LogSavePath + @"\simplify_log.txt");//日誌路徑,單文件存儲模式,採用組件信息 net_simplify_server.LogNet.SetMessageDegree(HslMessageDegree.DEBUG);//默認debug及以上級別日誌均進行存儲,根據須要自行選擇,DEBUG存儲的信息比較多 net_simplify_server.ReceiveStringEvent += Net_simplify_server_ReceiveStringEvent;//接收到字符串觸發 net_simplify_server.ReceivedBytesEvent += Net_simplify_server_ReceivedBytesEvent;//接收到字節觸發 net_simplify_server.ServerStart(17432);//網絡端口,此處使用了一個隨便填寫的端口 } catch (Exception ex) { SoftBasic.ShowExceptionMessage(ex); } } /// <summary> /// 接收來自客戶端的字節數據 /// </summary> /// <param name="state">網絡狀態</param> /// <param name="customer">字節數據,根據實際狀況選擇是否使用</param> /// <param name="data">來自客戶端的字節數據</param> private void Net_simplify_server_ReceivedBytesEvent(AsyncStateOne state, NetHandle customer, byte[] data) { if(customer==1000) { // 收到指令爲1000的請求時,返回1000長度的字節數組 net_simplify_server.SendMessage(state, customer, new byte[1000]); } else { net_simplify_server.SendMessage(state, customer, data); } } /*********************************************************************************************** * * 方法說明: 當接收到來自客戶端的數據的時候觸發的方法 * 特別注意: 若是你的數據處理中引起了異常,應用程序將會奔潰,SendMessage異常系統將會自動處理 * ************************************************************************************************/ /// <summary> /// 接收到來自客戶端的字符串數據,而後將結果發送回客戶端,注意:必須回髮結果 /// </summary> /// <param name="state">客戶端的地址</param> /// <param name="handle">用於自定義的指令頭,可不用,轉而使用data來區分</param> /// <param name="data">接收到的服務器的數據v/param> private void Net_simplify_server_ReceiveStringEvent(AsyncStateOne state, NetHandle handle, string data) { /******************************************************************************************* * * 說明:同步消息處理總站,應該根據不一樣的消息設置分流到不一樣的處理方法 * * 注意:處理完成後必須調用 net_simplify_server.SendMessage(state, customer, "處理結果字符串,能夠爲空"); * *******************************************************************************************/ if (handle == 1) { net_simplify_server.SendMessage(state, handle, "測試數據一"); } else if (handle == 2) { net_simplify_server.SendMessage(state, handle, "測試數據二"); } else if (handle == 3) { net_simplify_server.SendMessage(state, handle, "測試數據三"); } else {
// 這部分的代碼是必須的,即便你不作任何處理,也應該返回原數據 net_simplify_server.SendMessage(state, handle, data); } }
服務端的主要代碼都在上面的代碼段了,也沒多少代碼,關鍵是支持的請求多了以後,不停的使用 if...else 代碼會顯得不少很亂,因此此處的 Nethandle 這個值類型就是爲了解決這個問題而設計的,它本質上是一個 int 數據,咱們知道一個 int 是由4個字節組成,那麼byte[0]byte[1]byte[2]byte[3],那麼我能夠用byte[3](最高位)來做爲指令大類。byte[2]來做爲指令小類,byte[0]和byte[1]組成的 ushort 數據來做爲指令編號,因此上述的方法 Net_simplify_server_ReceiveStringEvent 中的細節能夠改爲下面:工具
/// <summary> /// 接收到來自客戶端的字符串數據,而後將結果發送回客戶端,注意:必須回髮結果 /// </summary> /// <param name="state">客戶端的地址</param> /// <param name="handle">用於自定義的指令頭,可不用,轉而使用data來區分</param> /// <param name="data">接收到的服務器的數據</param> private void Net_simplify_server_ReceiveStringEvent(AsyncStateOne state, NetHandle handle, string data) { /******************************************************************************************* * * 說明:同步消息處理總站,應該根據不一樣的消息設置分流到不一樣的處理方法 * * 注意:處理完成後必須調用 net_simplify_server.SendMessage(state, customer, "處理結果字符串,能夠爲空"); * *******************************************************************************************/ if (handle.CodeMajor == 1) { ProcessCodeMajorOne(state, handle, data); } else if (handle.CodeMajor == 2) { ProcessCodeMajorTwo(state, handle, data); } else if (handle.CodeMajor == 3) { ProcessCodeMajorThree(state, handle, data); } else { net_simplify_server.SendMessage(state, handle, data); } } private vode ProcessCodeMajorOne(AsyncStateOne state, NetHandle handle, string data) { if (handle.CodeIdentifier == 1) { // 下面能夠再if..else net_simplify_server.SendMessage(state, handle, "測試數據大類1,命令1,接收到的數據是:" + data); } else { net_simplify_server.SendMessage(state, handle, data); } } private vode ProcessCodeMajorTwo(AsyncStateOne state, NetHandle handle, string data) { if (handle.CodeIdentifier == 1) { // 下面能夠再if..else net_simplify_server.SendMessage(state, handle, "測試數據大類2,命令1,接收到的數據是:" + data); } else { net_simplify_server.SendMessage(state, handle, data); } } private vode ProcessCodeMajorThree(AsyncStateOne state, NetHandle handle, string data) { if (handle.CodeIdentifier == 1) { // 下面能夠再if..else net_simplify_server.SendMessage(state, handle, "測試數據大類3,命令1,接收到的數據是:" + data); } else { net_simplify_server.SendMessage(state, handle, data); } }
指令根據不一樣的功能進行歸類,會使代碼簡潔不少。oop
客戶端的程序相對簡單不少,只須要實例化一下就可使用了,並且該實例化對象的方法是線程安全的,因此在定義成靜態對象,在代碼的任何地方均可以使用,不須要再重複實例化,以下代碼是實例化:
// 用於訪問服務器數據的網絡對象類,必須修改這個端口參數,不然運行失敗 public static NetSimplifyClient Net_simplify_client { get; set; } = new NetSimplifyClient( new IPEndPoint(IPAddress.Parse("127.0.0.1"), 17432)) // 指定服務器的ip,和服務器設置的端口 { KeyToken = Guid.Empty, // 這個guid碼必需要服務器的一致,不然服務器會拒絕鏈接 ConnectTimeout = 5000,// 鏈接的超時時間 };
接下來就是讀取數據的展現了,返回的結果關聯到一個類 OperateResult<string> 這個類只包含了幾個公開的數據屬性,沒什麼實際的含義,一看就明白了。下面的代碼能夠放到button按鈕裏去測試
OperateResult<string> result = Net_simplify_client.ReadFromServer( new NetHandle(1,0,1), "發送的數據"); // 指示了大類1,子類0,編號1 if (result.IsSuccess) { // 按照上面服務器的代碼,此處顯示數據爲:"上傳成功!返回的數據:測試數據大類1,命令1,接收到的數據是:發送的數據" MessageBox.Show(result.Content); } else { MessageBox.Show("操做失敗!緣由:" + result.Message);// 失敗的緣由基本上是鏈接不上,若是GUID碼填寫錯誤,也會鏈接不上 }
失敗的緣由一般來自網絡異常,當你把服務器架設在雲端時,或是其餘的服務器電腦,若是訪問總是失敗,就要檢查防火牆是否容許指定端口網絡通訊了。
測試工具,當你在服務器端架設好同步網絡的後臺代碼後,想要進行快速測試服務器的狀態是否正確的時候,能夠經過下面的組件來實現數據測試:
測試工具在github上開源,屬於C-S架構模版的一部分,地址爲:
https://github.com/dathlin/ClientServerProject
必須帶有HslCommunication.dll和Newtonsoft.Json.dll組件放到一塊兒,這樣就能夠運行測試了:
首先先添加鏈接點:
接下來輸入鏈接信息,包括服務器的IP地址,同步網絡端口號,令牌信息
鏈接完成後,點擊下面圖片的1處,在2處會顯示固然鏈接的信息,而後在3處輸入指令,點擊4進行發送,就會顯示來自服務器的數據結果,如圖顯示返回了一個JOSN字符串信息: