C# Socket通信三大问题详解

 

来自:百度文库

 

·                                 C# Socket通信三大问题详解

C# Socket通信三大问题是什么呢?C# Socket通信三大问题的具体内容是什么呢?各自的特点是什么呢?那么本文就向你详细介绍C# Socket通信三大问题。

C# Socket通信三大问题是什么呢?让我们开始讲述:

C# Socket通信三大问题之数据包界限符问题。

根据原项目中交通部标准,在连续观测站中数据包中,使用﹤﹥两个字符表示有效数据包开始和结束。实际项目有各自的具体技术规范

C# Socket通信三大问题之数据包不连续问题。

TCP/IP等通信中,由于时延等原因,一个数据包被Socket做两次或多次接收,此时在接收第一个包后,必须保存到TSessionDatagramBuffer中,在以后一并处理

C# Socket通信三大问题包并发与重叠问题。

由于客户端发送过快或设备故障等原因,一次接收到一个半、两个或多个包文。此时,也需要处理、一个半、两个或多个包

先补充异步BeginReceive()回调函数EndReceiveData()中的数据包分合函数ResolveBuffer()

下面是C# Socket通信三大问题的实例演示:

1.            /// summary 

2.            /// 1) 报文界限字符为﹤﹥,其它为合法字符 

3.            /// 2) 按报文头、界限标志抽取报文,可能合并包文  

4.            /// 3) 如果一次收完数据,此时 DatagramBuffer 为空  

5.            /// 4) 否则转存到包文缓冲区 session.DatagramBuffer  

6.            /// /summary 

7.            private void ResolveBuffer(TSession session, int receivedSize)  

8.            {  

9.            // 上次留下的报文缓冲区非空(注意:必然含有开始字符 ﹤,空时不含 ﹤)  

10.        bool hasBeginChar = (session.DatagramBufferLength  0);   

11.         

12.        int packPos = 0;  // ReceiveBuffer 缓冲区中包的开始位置  

13.        int packLen = 0;  // 已经解析的接收缓冲区大小  

14.         

15.        byte dataByte = 0;  // 缓冲区字节  

16.        int subIndex = 0;   // 缓冲区下标  

17.         

18.        while (subIndex  receivedSize)  

19.        {  

20.           // 接收缓冲区数据,要与报文缓冲区 session.DatagramBuffer 同时考虑  

21.           dataByte = session.ReceiveBuffer[subIndex];  

22.             

23.           if (dataByte == TDatagram.BeginChar) // 是数据包的开始字符﹤,则前面的包文均要放弃  

24.           {  

25.          // ﹤前面有非空串(包括报文缓冲区),则前面是错包文,防止 AAAA,1,A 两个报文一次读现象  

26.          if (packLen  0)    

27.          {  

28.         Interlocked.Increment(ref _datagramCount);  // 前面有非空字符  

29.         Interlocked.Increment(ref _errorDatagramCount);  // 一个错误包  

30.         this.OnDatagramError();  

31.          }  

32.          session.ClearDatagramBuffer();  // 清空会话缓冲区,开始一个新包  

33.         

34.          packPos = subIndex;   // 新包起点,即﹤所在位置  

35.          packLen = 1;// 新包的长度(即﹤)  

36.          hasBeginChar = true;  // 新包有开始字符  

37.           }     

38.           else if (dataByte == TDatagram.EndChar)  // 数据包的结束字符  

39.           {  

40.          if (hasBeginChar)  // 两个缓冲区中有开始字符﹤  

41.          {  

42.         ++packLen;  // 长度包括结束字符﹥  

43.         

44.         // ﹥前面的为正确格式的包,则分析该包,并准备加入包队列  

45.         AnalyzeOneDatagram(session, packPos, packLen);  

46.         

47.         packPos = subIndex + 1;  // 新包起点。注意:subIndex 在循环最后处 + 1  

48.         packLen = 0;   // 新包长度  

49.          }  

50.          else  // ﹥前面没有开始字符,则认为结束字符﹥为一般字符,待后续的错误包处理  

51.          {  

52.         ++packLen;  //  hasBeginChar = false;  

53.          }  

54.           }  

55.           else  // 非界限字符﹤﹥,就是是一般字符,长度 + 1,待解析包处理  

56.           {  

57.          ++packLen;  

58.           }  

59.           ++subIndex;  // 增加下标号  

60.        }  // end while  

61.         

62.        if (packLen  0)  // 剩下的待处理串,分两种情况  

63.        {  

64.           // 剩下包文,已经包含首字符且不超长,转存到包文缓冲区中,待下次处理  

65.           if (hasBeginChar && packLen + 

66.        session.DatagramBufferLength = _maxDatagramSize)  

67.           {  

68.          session.CopyToDatagramBuffer(packPos, packLen);  

69.           }  

70.           else  // 不含首字符,或超长  

71.           {  

72.          Interlocked.Increment(ref _datagramCount);  

73.          Interlocked.Increment(ref _errorDatagramCount);  

74.         

75.          this.OnDatagramError();  

76.          session.ClearDatagramBuffer();  // 丢弃全部数据  

77.           }  

78.        }  

79.        }  

C# Socket通信三大问题之分析包文AnalyzeOneDatagram()函数代码补充如下:

80.        /// summary 

81.        /// 具有﹤﹥格式的数据包加入到队列中  

82.        /// /summary 

83.        private void AnalyzeOneDatagram(  

84.        TSession session, int packPos, int packLen)  

85.        {  

86.        if (packLen + session.DatagramBufferLength  _maxDatagramSize)    

87.        // 超过长度限制  

88.        {  

89.           Interlocked.Increment(ref _datagramCount);  

90.           Interlocked.Increment(ref _errorDatagramCount);  

91.           this.OnDatagramError();  

92.        }  

93.        else // 一个首尾字符相符的包,此时需要判断其类型  

94.        {  

95.           Interlocked.Increment(ref _datagramCount);  

96.           TDatagram datagram = new TDatagram();  

97.         

98.           if (!datagram.CheckDatagramKind())    

99.        // 包格式错误(只能是短期BG、或长期SG包)  

100.        {  

101.       Interlocked.Increment(ref _datagramCount);  

102.       Interlocked.Increment(ref _errorDatagramCount);  

103.       this.OnDatagramError();  

104.       datagram = null;  // 丢弃当前包  

105.        }  

106.        else  // 实时包、定期包,先解析数据,判断正误,并发回确认包  

107.        {  

108.       datagram.ResolveDatagram();  

109.       if (true)  // 正确的包才入包队列  

110.       {  

111.      Interlocked.Increment(ref _datagramQueueCount);  

112.      lock (_datagramQueue)  

113.      {  

114.     _datagramQueue.Enqueue(datagram);  // 数据包入队列  

115.      }  

116.       }  

117.       else 

118.       {  

119.      Interlocked.Increment(ref _errorDatagramCount);  

120.      this.OnDatagramError();  

121.       }  

122.        }  

123.     }  

124.     session.ClearDatagramBuffer();  // 清包文缓冲区  

125.    

C# Socket通信三大问题之TSession的拷贝转存数据包文的方法CopyToDatagramBuffer()代码如下:

126.     /// summary 

127.     /// 拷贝接收缓冲区的数据到数据缓冲区(即多次读一个包文)  

128.     /// /summary 

129.     public void CopyToDatagramBuffer(int startPos, int packLen)    

130.     {  

131.     int datagramLen = 0;  

132.     if (DatagramBuffer != null) datagramLen =   

133.     DatagramBuffer.Length;  

134.      

135.     // 调整长度(DataBuffer  null 不会出错)  

136.     Array.Resize(ref DatagramBuffer,   

137.     datagramLen + packLen);  

138.      

139.     // 拷贝到数据就缓冲区  

140.     Array.Copy(ReceiveBuffer, startPos,   

141.     DatagramBuffer, datagramLen, packLen);  

142.     }  

代码中注释比较详细了,下面指出C# Socket通信三大问题实例开发思路:

使用TSession会话对象的字节数组ReceiveBuffer保存BeginReceiver()接收到的数据,使用字节数组DatagramBuffer保存一次接收后分解或合并的剩下的包文。本项目中,由于是5分钟一个包,正常情况下不需要用到DatagramBuffer数组

处理ReceiveBuffer中的字节数据包时,先考虑DatagramBuffer是否有开始字符﹤。如果有,则当前包文是前个包文的补充,否则前个包文是错误的。正确的包文可能存在于两个缓冲区中,见分析函数AnalyzeOneDatagram()

分析完接收数据包后,剩下的转存到DatagramBuffer中,见函数CopyToDatagramBuffer()

设计时考虑的另一个重要问题就是处理速度。如果自动观测站达到100个,此时5*60=300秒钟就有100个包,即每3秒种一个包,不存在处理速度慢问题。但是,真正耗时的是判断包是否重复!特别地,当设备故障时存在混乱上传数据包现象,此时将存在大量的重复包。笔者采用了所谓的区间判重算法,较好地解决了判重速度问题,使得系统具有很好的可伸缩性(分析算法的论文被EI核心版收录,呵呵,意外收获)。事实上,前年的交通部接收服务器还不具备该项功能,可能是太费时间了。

还有,就是在.NET Framework的托管CLR下,系统本身的响应速度如何?当时的确没有把握,认为只要稳定性和速度满足要求就行了。三年半运行情况表明,系统有良好的处理速度、很好的稳定性、满足了部省要求。

C# Socket通信三大问题的基本内容就向你介绍到这里了,希望对你了解和学习C# Socket通信三大问题有所帮助。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值