【.NET類庫】通過SharpSocket進行TCP/UDP通信數據傳輸


類庫作用:

用於基於TCP/UDP協議的數據通信,調用簡單,高效。 封裝了和業務無關的底層細節,讓開發人員可以專注於做業務

完善的示例代碼:

針對類庫的幾種用法,都提供了較為詳細的示例代碼

 

一、TCP收發二進制數據:

(服務端)

通過SocketFactory工廠對象,得到一個BinaryTcpServer實例,參數為 監聽的端口號。

然后給tcpServerIntance對象綁定事件, 如客戶端數量變更、客戶端已連接、客戶端失連接、收到客戶端消息等等

 #region 獲取ITcpServer的示例

                if (tcpServerIntance == null)
                {
                    tcpServerIntance =
                        SocketFactory.GetBinaryTcpServer(int.Parse(txtPort.Text.Trim()), new BinaryFormattHelper());

                    //綁定事件
                    this.tcpServerIntance.ClientCountChanged += new SGDelegate<int>(ClientCountChanged);
                    this.tcpServerIntance.ClientConnected += new SGDelegate<System.Net.IPEndPoint>(ClientConnected);
                    this.tcpServerIntance.ClientDisconnected += new SGDelegate<System.Net.IPEndPoint>(ClientDisconnected);
                    this.tcpServerIntance.MessageReceived += new SGDelegate<IPEndPoint, byte[]>(MessageReceived);
                }
                #endregion

(客戶端) 

通過SocketFactory工廠對象,創建一個BinaryTcpClient客戶端對象,參數為服務端的IP,服務端的端口號

然后給clientInstance對象綁定相關的事件方法,如斷開連接、重連成功等

//獲取tcp客戶端接口實例
                clientInstance = SocketFactory.GetBinaryTcpClient(this.txtIP.Text, int.Parse(this.txtPort.Text), new BinaryFormattHelper());

                //綁定事件
                clientInstance.MessageReceived += new SGDelegate<System.Net.IPEndPoint, byte[]>(MessageReceived);
                clientInstance.ConnectionDisconnected += new SGDelegate(ConnectionInterrupted);
                clientInstance.ConnectionReconnectSucceed += new SGDelegate(ConnectionRebuildSucceed);

                //啟動掉線自動重連 
                clientInstance.AutoReconnect = true;

                //開始初始化,SharpSocket將初始化和服務端的連接
                clientInstance.Initialize();

 

為了方便演示效果,服務端和客戶端分別都做成了WinForm窗體應用程序,這樣看起來更直觀:

啟動服務端,啟動之后服務端會監聽本機9000端口。 

 

然后啟動一個客戶端,IP默認本機IP,端口號為服務端的監聽端口9000,點擊“連接”按鈕,提示連接成功

此時看一下服務端的界面,會發現服務端監測到了客戶端的連接。

 

數據傳輸:

我們在客戶端選擇兩個數字,然后選擇一個運算符號,把這些信息發送給服務端,我們期望服務端接受這些信息,執行相應的計算,並返回計算結果給客戶端

 

點擊提交

可以看到運算的結果已經從服務端獲取

 

數據是如何從客戶端傳給服務端?服務端又是如何返回結果給客戶端呢?

(客戶端發送數據給服務端)

//請求消息體
            RequestFormat contract = new RequestFormat(int.Parse(this.textBox1.Text), int.Parse(this.textBox2.Text));
            byte[] bBody = SerializeHelper.SerializeObject(contract);

            //消息頭
            MessageHead head = new MessageHead(bBody.Length, msgType);
            byte[] bHead = head.ToStream();

            //構建請求消息
            byte[] reqMessage = new byte[bHead.Length + bBody.Length];
            Buffer.BlockCopy(bHead, 0, reqMessage, 0, bHead.Length);
            Buffer.BlockCopy(bBody, 0, reqMessage, bHead.Length, bBody.Length);

            //發送請求消息
            clientInstance.PostDataToServer(reqMessage);

(服務端返回數據給客戶端)

//回復消息體
            ResponseFormat response = new ResponseFormat(request.Number1, request.Number2, operationType, result);
            byte[] bReponse = SerializeHelper.SerializeObject(response); 
            
            //回復消息頭
            MessageHead head = new MessageHead(bReponse.Length, MessageType.Result);
            byte[] bHead = head.ToStream();

            //構建回復消息
            byte[] resMessage = new byte[bHead.Length + bReponse.Length];
            Buffer.BlockCopy(bHead, 0, resMessage, 0, bHead.Length);
            Buffer.BlockCopy(bReponse, 0, resMessage, bHead.Length, bReponse.Length);

            //發送回復消息
            tcpServerIntance.PostDataToClient(client, resMessage);

可以看到,都是通過byte[]的形式進行數據傳遞的,用於傳遞的byte[]代表一個消息,消息包含消息頭和消息體,消息頭是固定長度的,具體長度要根據服務端和客戶端直接商定的協議來確定

在實例代碼中,消息頭的長度HeadLength為8位

 

二、TCP收發文本數據

服務端:

創建TextTcpServer對象,綁定事件,然后啟動監聽

 #region 獲取ITcpServer的示例

                if (tcpServerIntance == null)
                {
                    //DefaultTextFormatHelper是自帶的使用UTF8編碼,兼容中英文
                    tcpServerIntance =
                        SocketFactory.GetTextTcpServer(int.Parse(txtPort.Text.Trim()), new DefaultTextFormatHelper("\0"));

                    //綁定事件
                    this.tcpServerIntance.ClientCountChanged += new SGDelegate<int>(ClientCountChanged);
                    this.tcpServerIntance.ClientConnected += new SGDelegate<System.Net.IPEndPoint>(ClientConnected);
                    this.tcpServerIntance.ClientDisconnected += new SGDelegate<System.Net.IPEndPoint>(ClientDisconnected);
                    this.tcpServerIntance.MessageReceived += new SGDelegate<IPEndPoint, byte[]>(MessageReceived);
                }
                #endregion

                #region 啟動監聽
                tcpServerIntance.Initialize();
                #endregion

 

客戶端:

創建TextTcpClient對象,綁定事件,執行Initialize()初始化方法

//初始化並啟動客戶端引擎(TCP、文本協議)
                clientInstance = SocketFactory.GetTextTcpClient(this.txtIP.Text, int.Parse(this.txtPort.Text), new DefaultTextFormatHelper("\0"));
                clientInstance.MessageReceived += new SGDelegate<System.Net.IPEndPoint, byte[]>(MessageReceived);
                clientInstance.AutoReconnect = true;//啟動掉線自動重連                
                clientInstance.ConnectionDisconnected += new SGDelegate(ConnectionDisconnected);
                clientInstance.ConnectionReconnectSucceed += new SGDelegate(ConnectionRebuildSucceed);
                clientInstance.Initialize();

 

演示效果:

啟動服務端並監聽端口

 

啟動客戶端並連接端口

 

 連接成功之后,服務端會有上線提示,並且會自動記錄上線客戶端數量

 

客戶端嘗試一下向服務端發送數據,服務端接收到了客戶端發送的數據,並展示

嘗試一下服務端向客戶端發送數據,試試發送json字符串。

客戶端收到了服務端發送的json字符串

 

 那么客戶端具體是如何把數據發送給服務端?服務端又是如何進行回復的呢?

客戶端發送數據

//將待發送的原始字符串加上 "\0"字符,代表一幀的結尾,方便服務端根據這個來過濾
            string msg = this.txtMsg.Text + "\0";

            //使用UTF-8編碼數據
            byte[] bMsg = System.Text.Encoding.UTF8.GetBytes(msg);

            //發走
            clientInstance.SendDataToServer(bMsg);

 

 服務端接受數據

//使用UTF-8編碼
            string msg = System.Text.Encoding.UTF8.GetString(bMsg); 
            //將結束標記"\0"去掉,得到的就是原始字符串
            msg = msg.Substring(0, msg.Length - 1); 

 

服務端回復數據

 //原始要發送的字符串加上一個結尾字符,由於使用的是DefaultTextFormatHelper,因此這里用"\0" 表示一個消息的結尾
                string msg = this.textBox_msg.Text + "\0";

                //DefaultTextFormatHelper使用UTF-8編碼
                byte[] bMsg = System.Text.Encoding.UTF8.GetBytes(msg);

                tcpServerIntance.SendDataToClient(client, bMsg);

 

可以看到,在進行字符串、json或者xml等一些非結構化的數據傳輸時,也是先將內容轉化成字節數組。

與TCP的二進制數據傳輸不同的時,這里不區分消息頭和消息體,只是由客戶端和服務端預定義了幀的結束符,在每一幀消息的末尾加上這個結束符,方便服務端和客戶端進行解析

 

三、UDP收發任意數據

基於UDP協議的數據通訊,不需要客戶端提前建立連接

(服務端)

服務端通過SocketFactory.GetUdp()方法,創建UDP通信實例,並設定本端使用的端口號,注冊消息事件並初始化

//創建一個接口實例,然后就可以操作它了
                udpServerInstance = SocketFactory.GetUdp();

                //設置本端使用的端口號
                udpServerInstance.Port = int.Parse(this.edtPort.Text);

                //訂閱本接口的收到數據的事件通知,當收到數據后,自動回調您注冊的方法
                udpServerInstance.MessageReceived += new SGDelegate<IPEndPoint, byte[]>(MessageReceived);

                //啟動即可
                udpServerInstance.Initialize();

(客戶端)

根據IP和端口號創建服務端終結點,通過SocketFactory.GetUdp()創建UDP實例

//得到服務端終結點
            serverEndPoint = new IPEndPoint(IPAddress.Parse(this.edtIP.Text), int.Parse(this.edtPort.Text));

            if (this.udpClientInstance == null)
            {
                //初始化並啟動客戶端引擎(UDP)
                udpClientInstance = SocketFactory.GetUdp();

                //訂閱接收到數據的事件
                udpClientInstance.MessageReceived += new SGDelegate<System.Net.IPEndPoint, byte[]>(MessageReceived);

                //啟動UDP連接
                udpClientInstance.Initialize();

客戶端根據用戶請求,構建消息頭和消息體,並調用udpClientInstance.SendData(serverEndPoint,reqMessage);方法向服務端發送數據

int msgType = this.cmdOpType.SelectedIndex == 0 ? MessageType.Add : MessageType.Multiple;

            //請求消息體
            RequestFormat contract = new RequestFormat(int.Parse(this.edtFirst.Text), int.Parse(this.edtSecond.Text));
            byte[] bBody = SerializeHelper.SerializeObject(contract);

            //消息頭
            MessageHead head = new MessageHead(bBody.Length, msgType);
            byte[] bHead = head.ToStream();

            //構建請求消息
            byte[] reqMessage = new byte[bHead.Length + bBody.Length];
            Buffer.BlockCopy(bHead, 0, reqMessage, 0, bHead.Length);
            Buffer.BlockCopy(bBody, 0, reqMessage, bHead.Length, bBody.Length);

            //發送請求消息
            udpClientInstance.SendData(serverEndPoint, reqMessage);

 

服務端收到數據之后,解析收到的信息,執行相應的運算操作,並把結果返回給客戶端

#region 解析消息體
            RequestFormat request = (RequestFormat)SerializeHelper.DeserializeBytes(bMsg, MessageHead.HeadLength, bMsg.Length - MessageHead.HeadLength); 
            int result = 0;
            string operationType = "";
            if (msgType == MessageType.Add)
            {
                result = request.Number1 + request.Number2;
                operationType = "加法";
            }
            else if (msgType == MessageType.Multiple)
            {
                result = request.Number1 * request.Number2;
                operationType = "乘法";
            }
            else
            {
                operationType = "錯誤的操作類型";
            }
            #endregion

            #region 顯示請求
            string msg = string.Format("請求類型:{0},操作數1:{1},操作數2:{2}", operationType, request.Number1 , request.Number2);
            ShowStr(client, msg);
            #endregion

            #region 回復消息體
            ResponseFormat response = new ResponseFormat(request.Number1, request.Number2, operationType, result);
            byte[] bReponse = SerializeHelper.SerializeObject(response); 
            #endregion

            #region 回復消息頭
            MessageHead head = new MessageHead(bReponse.Length, MessageType.Result);
            byte[] bHead = head.ToStream();
            #endregion

            #region 構建回復消息
            byte[] resMessage = new byte[bHead.Length + bReponse.Length];
            Buffer.BlockCopy(bHead, 0, resMessage, 0, bHead.Length);
            Buffer.BlockCopy(bReponse, 0, resMessage, bHead.Length, bReponse.Length);
            #endregion

            #region 發送回復消息
            udpServerInstance.SendData(client, resMessage);
            #endregion

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM