【.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

 

posted @ 2019-08-13 10:23  寂寞姜大虎  阅读(1571)  评论(0编辑  收藏  举报