C# 网络通信功能 同步数据交互开发

前言


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

 

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

?

1

Install-Package HslCommunication

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

技术支持QQ群:592132877 (组件的版本更新细节也将第一时间在群里发布)

 

 

Summary


 

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

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

 

Reference


 

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

?

1

2

using HslCommunication;

using HslCommunication.Enthernet;

How to Use


 

服务器端

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

// 用户同步数据传送的引擎

        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

            {<br>                // 这部分的代码是必须的,即使你不做任何处理,也应该返回原数据

                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 中的细节可以改成下面:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

/// <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);

    }

}

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

 

客户端

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

?

1

2

3

4

5

6

7

// 用于访问服务器数据的网络对象类,必须修改这个端口参数,否则运行失败

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按钮里去测试

?

1

2

3

4

5

6

7

8

9

10

11

12

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字符串信息:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值