本文将使用一个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字符串信息: