前言


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

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

Install-Package HslCommunication

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

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

Summary


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

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

Reference


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

using HslCommunication;
using HslCommunication.Enthernet;

How to Use


服务器端

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

// 用户同步数据传送的引擎
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);
}
}

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

客户端

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

        // 用于访问服务器数据的网络对象类,必须修改这个端口参数,否则运行失败
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码填写错误,也会连接不上
}

  

失败说明

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

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. CentOS7查看systemctl 控制的服务的相关配置

    例如,启动配置文件 [root@Docker_Machine_192.168.31.130 ~]# systemctl show --property=FragmentPath docker Frag ...

  2. Shell data、timedatectl

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

  3. 关于oracle result_cache

    结果集缓存 和聚合物化视图类似,报表系统和数据仓库系统是最适合结果集缓存的,这些系统通常具有大量复杂的SQL,其中不少子查询包含聚合函数,如果能够尽可能重用这些已经计算过的聚合结果集,将极大的提升系统 ...

  4. Springboot 使用PageHelper分页插件实现分页

    一.pom文件中引入依赖 二.application.properties中配置以下内容(二选一方案) 第一种:pagehelper.helper-dialect=mysqlpagehelper.re ...

  5. 2018-2019-1 20189206 《Linux内核原理与分析》第八周作业

    #linux内核分析学习笔记 --第七章 可执行程序工作原理 学习目标:了解一个可执行程序是如何作为一个进程工作的. ELF文件 目标文件:是指由汇编产生的(*.o)文件和可执行文件. 即 可执行或可 ...

  6. WinForm中预览Office文件

    WinForm预览Office文档 使用WinForm, WPF, Office组件 原理:使用Office COM组件将Word,Excel转换为XPS文档, 将WPF的DocumentViewer ...

  7. (转) Ensemble Methods for Deep Learning Neural Networks to Reduce Variance and Improve Performance

    Ensemble Methods for Deep Learning Neural Networks to Reduce Variance and Improve Performance 2018-1 ...

  8. MapReduce编程:单词去重

    编程实现单词去重要用到NullWritable类型. NullWritable: NullWritable 是一种特殊的Writable 类型,由于它的序列化是零长度的,所以没有字节被写入流或从流中读 ...

  9. ASP.NET图片上传(配合jquery.from.js 插件)

    前端: js:        function AjaxKouBeiShopEdit() { var options = {                dataType: "json&q ...

  10. Docker应用

    1.tomcat容器创建 docker run -d --name Jdd_tomcat  -p 8081:8080 tomcat [root@localhost etc]# docker run - ...