前言


本文将使用一个Nuget公开的组件技术来实现一对多的数据通信功能,提供了一些简单的API,来方便的向服务器进行数据请求。

在visual studio 中的Nuget管理器中可以下载安装,也可以直接在Nuget控制台输入下面的指令安装:

  1. Install-Package HslCommunication

Nuget安装教程  http://www.cnblogs.com/dathlin/p/7705014.html

联系作者及加群方式(激活码在群里发放):http://www.hslcommunication.cn/Cooperation

Summary


一个用于同步数据交互的网络通信类,在实际的程序开发中,我们经常会碰到这样的需要,我们需要向服务器请求一些数据,然后接收从服务器返回的数据,数据类型通常为 byte[] 或是 string ,类型,所以通常在服务器端会配置一个数据处理总站,每次请求都会带有一个信号头,用于服务器区分不同的信息机制,而我们可以使用组件中的 NetSimplifyServerNetSimplifyClient 类来完成功能。

该通讯类对所有的底层进行了封装,包含了协议头定义,令牌验证,数据的加密解密,压缩和解压缩,可以安全的在局域网和广域网上进行数据传播,服务器端还增加了防止恶意连接机制,有效抵制来自网络的恶意网络攻击。

Reference


日志组件所有的功能类都在 HslCommunicationHslCommunication.Enthernet 命名空间,所以再使用之前先添加

  1. using HslCommunication;
  2. using HslCommunication.Enthernet;

How to Use


服务器端

我们先要在服务器端进行创建网络监听,这样才能让客户端连接到服务器,服务器需要先实例化及初始化代码如下,代码直接在服务器主窗口下面:

  1. // 用户同步数据传送的引擎
  2. private NetSimplifyServer net_simplify_server = new NetSimplifyServer(); //实例化
  3. // 同步传送数据的初始化
  4. private void Net_Simplify_Server_Initialization()
  5. {
  6. try
  7. {
  8. net_simplify_server.KeyToken = Guid.Empty;//设置身份令牌,本质就是一个GUID码,验证客户端使用
  9. net_simplify_server.LogNet = new LogNetSingle(LogSavePath + @"\simplify_log.txt");//日志路径,单文件存储模式,采用组件信息
  10. net_simplify_server.LogNet.SetMessageDegree(HslMessageDegree.DEBUG);//默认debug及以上级别日志均进行存储,根据需要自行选择,DEBUG存储的信息比较多
  11. net_simplify_server.ReceiveStringEvent += Net_simplify_server_ReceiveStringEvent;//接收到字符串触发
  12. net_simplify_server.ReceivedBytesEvent += Net_simplify_server_ReceivedBytesEvent;//接收到字节触发
  13. net_simplify_server.ServerStart(17432);//网络端口,此处使用了一个随便填写的端口
  14. }
  15. catch (Exception ex)
  16. {
  17. SoftBasic.ShowExceptionMessage(ex);
  18. }
  19. }
  20.  
  21. /// <summary>
  22. /// 接收来自客户端的字节数据
  23. /// </summary>
  24. /// <param name="state">网络状态</param>
  25. /// <param name="customer">字节数据,根据实际情况选择是否使用</param>
  26. /// <param name="data">来自客户端的字节数据</param>
  27. private void Net_simplify_server_ReceivedBytesEvent(AsyncStateOne state, NetHandle customer, byte[] data)
  28. {
  29. if(customer==1000)
  30. {
  31. // 收到指令为1000的请求时,返回1000长度的字节数组
  32. net_simplify_server.SendMessage(state, customer, new byte[1000]);
  33. }
  34. else
  35. {
  36. net_simplify_server.SendMessage(state, customer, data);
  37. }
  38. }
  39.  
  40. /***********************************************************************************************
  41. *
  42. * 方法说明: 当接收到来自客户端的数据的时候触发的方法
  43. * 特别注意: 如果你的数据处理中引发了异常,应用程序将会奔溃,SendMessage异常系统将会自动处理
  44. *
  45. ************************************************************************************************/
  46.  
  47. /// <summary>
  48. /// 接收到来自客户端的字符串数据,然后将结果发送回客户端,注意:必须回发结果
  49. /// </summary>
  50. /// <param name="state">客户端的地址</param>
  51. /// <param name="handle">用于自定义的指令头,可不用,转而使用data来区分</param>
  52. /// <param name="data">接收到的服务器的数据v/param>
  53. private void Net_simplify_server_ReceiveStringEvent(AsyncStateOne state, NetHandle handle, string data)
  54. {
  55.  
  56. /*******************************************************************************************
  57. *
  58. * 说明:同步消息处理总站,应该根据不同的消息设置分流到不同的处理方法
  59. *
  60. * 注意:处理完成后必须调用 net_simplify_server.SendMessage(state, customer, "处理结果字符串,可以为空");
  61. *
  62. *******************************************************************************************/
  63.  
  64. if (handle == 1)
  65. {
  66. net_simplify_server.SendMessage(state, handle, "测试数据一");
  67. }
  68. else if (handle == 2)
  69. {
  70. net_simplify_server.SendMessage(state, handle, "测试数据二");
  71. }
  72. else if (handle == 3)
  73. {
  74. net_simplify_server.SendMessage(state, handle, "测试数据三");
  75. }
  76. else
  77. {
    // 这部分的代码是必须的,即使你不做任何处理,也应该返回原数据
  78. net_simplify_server.SendMessage(state, handle, data);
  79. }
  80. }

服务端的主要代码都在上面的代码段了,也没多少代码,关键是支持的请求多了之后,不停的使用 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 中的细节可以改成下面:

  1. /// <summary>
  2. /// 接收到来自客户端的字符串数据,然后将结果发送回客户端,注意:必须回发结果
  3. /// </summary>
  4. /// <param name="state">客户端的地址</param>
  5. /// <param name="handle">用于自定义的指令头,可不用,转而使用data来区分</param>
  6. /// <param name="data">接收到的服务器的数据</param>
  7. private void Net_simplify_server_ReceiveStringEvent(AsyncStateOne state, NetHandle handle, string data)
  8. {
  9.  
  10. /*******************************************************************************************
  11. *
  12. * 说明:同步消息处理总站,应该根据不同的消息设置分流到不同的处理方法
  13. *
  14. * 注意:处理完成后必须调用 net_simplify_server.SendMessage(state, customer, "处理结果字符串,可以为空");
  15. *
  16. *******************************************************************************************/
  17.  
  18. if (handle.CodeMajor == 1)
  19. {
  20. ProcessCodeMajorOne(state, handle, data);
  21. }
  22. else if (handle.CodeMajor == 2)
  23. {
  24. ProcessCodeMajorTwo(state, handle, data);
  25. }
  26. else if (handle.CodeMajor == 3)
  27. {
  28. ProcessCodeMajorThree(state, handle, data);
  29. }
  30. else
  31. {
  32. net_simplify_server.SendMessage(state, handle, data);
  33. }
  34. }
  35.  
  36. private vode ProcessCodeMajorOne(AsyncStateOne state, NetHandle handle, string data)
  37. {
  38. if (handle.CodeIdentifier == 1)
  39. {
  40. // 下面可以再if..else
  41. net_simplify_server.SendMessage(state, handle, "测试数据大类1,命令1,接收到的数据是:" + data);
  42. }
  43. else
  44. {
  45. net_simplify_server.SendMessage(state, handle, data);
  46. }
  47. }
  48.  
  49. private vode ProcessCodeMajorTwo(AsyncStateOne state, NetHandle handle, string data)
  50. {
  51. if (handle.CodeIdentifier == 1)
  52. {
  53. // 下面可以再if..else
  54. net_simplify_server.SendMessage(state, handle, "测试数据大类2,命令1,接收到的数据是:" + data);
  55. }
  56. else
  57. {
  58. net_simplify_server.SendMessage(state, handle, data);
  59. }
  60. }
  61.  
  62. private vode ProcessCodeMajorThree(AsyncStateOne state, NetHandle handle, string data)
  63. {
  64. if (handle.CodeIdentifier == 1)
  65. {
  66. // 下面可以再if..else
  67. net_simplify_server.SendMessage(state, handle, "测试数据大类3,命令1,接收到的数据是:" + data);
  68. }
  69. else
  70. {
  71. net_simplify_server.SendMessage(state, handle, data);
  72. }
  73. }

  指令根据不同的功能进行归类,会使代码简洁很多。

客户端

客户端的程序相对简单很多,只需要实例化一下就可以使用了,而且该实例化对象的方法是线程安全的,所以在定义成静态对象,在代码的任何地方都可以使用,不需要再重复实例化,如下代码是实例化:

  1. // 用于访问服务器数据的网络对象类,必须修改这个端口参数,否则运行失败
  2. public static NetSimplifyClient Net_simplify_client { get; set; } = new NetSimplifyClient(
  3. new IPEndPoint(IPAddress.Parse("127.0.0.1"), 17432)) // 指定服务器的ip,和服务器设置的端口
  4. {
  5. KeyToken = Guid.Empty, // 这个guid码必须要服务器的一致,否则服务器会拒绝连接
  6. ConnectTimeout = 5000,// 连接的超时时间
  7. };

接下来就是读取数据的展示了,返回的结果关联到一个类 OperateResult<string> 这个类只包含了几个公开的数据属性,没什么实际的含义,一看就明白了。下面的代码可以放到button按钮里去测试

  1. OperateResult<string> result = Net_simplify_client.ReadFromServer(
  2. new NetHandle(1,0,1), "发送的数据"); // 指示了大类1,子类0,编号1
  3.  
  4. if (result.IsSuccess)
  5. {
  6. // 按照上面服务器的代码,此处显示数据为:"上传成功!返回的数据:测试数据大类1,命令1,接收到的数据是:发送的数据"
  7. MessageBox.Show(result.Content);
  8. }
  9. else
  10. {
  11. MessageBox.Show("操作失败!原因:" + result.Message);// 失败的原因基本上是连接不上,如果GUID码填写错误,也会连接不上
  12. }

  

失败说明

失败的原因通常来自网络异常,当你把服务器架设在云端时,或是其他的服务器电脑,如果访问老是失败,就要检查防火墙是否允许指定端口网络通信了。

Test Client


测试工具,当你在服务器端架设好同步网络的后台代码后,想要进行快速测试服务器的状态是否正确的时候,可以通过下面的组件来实现数据测试:

测试工具在github上开源,属于C-S架构模版的一部分,地址为:

https://github.com/dathlin/ClientServerProject

必须带有HslCommunication.dll和Newtonsoft.Json.dll组件放到一起,这样就可以运行测试了:

首先先添加连接点:

接下来输入连接信息,包括服务器的IP地址,同步网络端口号,令牌信息

连接完成后,点击下面图片的1处,在2处会显示当然连接的信息,然后在3处输入指令,点击4进行发送,就会显示来自服务器的数据结果,如图显示返回了一个JOSN字符串信息:

C# 网络通信功能 同步数据交互开发的更多相关文章

  1. SQL数据同步到ELK(四)- 利用SQL SERVER Track Data相关功能同步数据(上)

    一.相关文档 老规矩,为了避免我的解释误导大家,请大家务必通过官网了解一波SQL SERVER的相关功能. 文档地址: 整体介绍文档:https://docs.microsoft.com/en-us/ ...

  2. 功能间(两个form)数据交互的编程方法

    功能间数据交互的编程方法 现在框架具有在两个打开的功能之间进行通讯的机制.通讯是指,一个功能调用另外一个功能的方法,或者传递一些数据,并得到返回结果.比如处置单打开结算单,结算单保存后,将结算单号反填 ...

  3. Hybrid小程序混合开发之路 - 数据交互

    HTML+CSS是历史悠久.超高自由度.控制精准.表现能力极强.编码简单.学习门槛超低.真跨平台的一种UI界面开发方式. 本文介绍的是微信小程序和H5混合开发的一种数据交互方式. 很多应用在原生界面中 ...

  4. 用canal监控binlog并实现mysql定制同步数据的功能

    业务背景 写任何工具都不能脱离实际业务的背景.开始这个项目的时候是因为现有的项目中数据分布太零碎,零零散散的分布在好几个数据库中,没有统一的数据库来收集这些数据.这种情况下想做一个大而全的会员中心系统 ...

  5. Phonegap开发的前后台数据交互

    在用Phonegap开发时,需要进行前后台数据交互,在网上找资料,很多东西让人一头雾水,最后借鉴了下面的博客: http://blog.sina.com.cn/s/blog_681929ae01017 ...

  6. 前后端数据交互处理基于原生JS模板引擎开发

    json数据错误处理,把json文件数据复制到----> https://www.bejson.com/ 在线解析json 这样能直观的了解到是否是json数据写错,在控制台打断点,那里错误打那 ...

  7. STM32L476应用开发之四:触摸屏驱动与数据交互

    数据交互可以说是任何一台仪器都需要的功能.我们的便携式气体分析仪,需要人来操作和配置,所以触摸屏就是我们必然的一个选择.本次我们计划采用3.5寸显示屏,串口通讯. 1.硬件设计 前面我们实验了串行通讯 ...

  8. GoAhead4.1.0 开发总结三(GoAction+Ajax实现局部数据交互)

    环境 官方文档:https://www.embedthis.com/goahead/doc/ 源码下载: goahead-4.1.0-src.tgz 系统平台:Ubuntu 12.04.4 gcc v ...

  9. vue前后台数据交互vue-resource文档

    地址:https://segmentfault.com/a/1190000007087934 Vue可以构建一个完全不依赖后端服务的应用,同时也可以与服务端进行数据交互来同步界面的动态更新. Vue通 ...

随机推荐

  1. Python Kivy writes / read the file on the SD card

    Path to SD card from jnius import autoclass # SDcard Android # Get path to SD card Android try: Envi ...

  2. Shell data、timedatectl

     data系统时间管理命令 命令date +%F xxxx—xx--xx #查看当前日期. 命令date +%T xx:xx:xx #查看当前时间. 命令date +%y xx #年2位 命令date ...

  3. C#使用NPOI导出Excel

    当记录数超出65536时,有两种方式处理: 一是调用WriteToDownLoad65536方法建立多个Excel. 二是调用WriteToDownLoad方法在同一个Excel中建多个Sheet. ...

  4. 用mint-ui picker组件 实现省市区三级联动

    公司上一期项目中新增了省市区滑动三级联动效果,用的是mint-ui的picker组件和popup组件,效果如下:点击确定换地区,点击取消不变 省市区数据是后台给的(根据上一级的id,获取下一级数据列表 ...

  5. Vue父子组件传值 | 父传子 | 子传父

    父传子 父容器 <template> <div> <zdy :module='test'></zdy> </div> </templa ...

  6. 【Mac AndroidStudio】download gradle fail问题

    第一次运行application时,会发现一直在download gradle,而且进度一直卡着.这时,可以直接拷贝download的链接,粘贴到浏览器下载.下载完了.然后,可以用命令行在用户目录下o ...

  7. vivado 创建PS工程

    前言 本文简要介绍在vivado中创建PS工程.单纯使用zynq芯片的PS部分就像使用普通ARM芯片一样,只是多了建立Zynq硬件系统这一个步骤.vivado创建PL工程参见此处 新建工程 与viva ...

  8. 在 Linux 上使用 VirtualBox 的命令行管理界面

    VirtualBox 拥有一套命令行工具,你可以使用 VirtualBox 的命令行界面 (CLI) 对远程无界面的服务器上的虚拟机进行管理操作.在这篇教程中,你将会学到如何在没有 GUI 的情况下使 ...

  9. POJ 3984(DFS入门题 +stack储存路径)

    POJ 3984 Description 定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, ...

  10. SpringBoot mybatis配置

    首先pom.xml <!-- mybatis 配置 --> <dependency> <groupId>org.mybatis.spring.boot</gr ...