C# Socket通信三大问题详解

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

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

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

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

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

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

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.   // ﹤前面有非空串(包括报文缓冲区),则前面是错包文,防止 AAA﹤A,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()函数代码补充如下:

  1. /// ﹤summary﹥  
  2. /// 具有﹤﹥格式的数据包加入到队列中  
  3. /// ﹤/summary﹥  
  4. private void AnalyzeOneDatagram(  
  5. TSession session, int packPos, int packLen)  
  6. {  
  7. if (packLen + session.DatagramBufferLength ﹥ _maxDatagramSize)    
  8. // 超过长度限制  
  9. {  
  10.    Interlocked.Increment(ref _datagramCount);  
  11.    Interlocked.Increment(ref _errorDatagramCount);  
  12.    this.OnDatagramError();  
  13. }  
  14. else // 一个首尾字符相符的包,此时需要判断其类型  
  15. {  
  16.    Interlocked.Increment(ref _datagramCount);  
  17.    TDatagram datagram = new TDatagram();  
  18.  
  19.    if (!datagram.CheckDatagramKind())    
  20. // 包格式错误(只能是短期BG、或长期SG包)  
  21.    {  
  22.   Interlocked.Increment(ref _datagramCount);  
  23.   Interlocked.Increment(ref _errorDatagramCount);  
  24.   this.OnDatagramError();  
  25.   datagram = null;  // 丢弃当前包  
  26.    }  
  27.    else  // 实时包、定期包,先解析数据,判断正误,并发回确认包  
  28.    {  
  29.   datagram.ResolveDatagram();  
  30.   if (true)  // 正确的包才入包队列  
  31.   {  
  32.  Interlocked.Increment(ref _datagramQueueCount);  
  33.  lock (_datagramQueue)  
  34.  {  
  35. _datagramQueue.Enqueue(datagram);  // 数据包入队列  
  36.  }  
  37.   }  
  38.   else 
  39.   {  
  40.  Interlocked.Increment(ref _errorDatagramCount);  
  41.  this.OnDatagramError();  
  42.   }  
  43.    }  
  44. }  
  45. session.ClearDatagramBuffer();  // 清包文缓冲区  

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

  1. /// ﹤summary﹥  
  2. /// 拷贝接收缓冲区的数据到数据缓冲区(即多次读一个包文)  
  3. /// ﹤/summary﹥  
  4. public void CopyToDatagramBuffer(int startPos, int packLen)    
  5. {  
  6. int datagramLen = 0;  
  7. if (DatagramBuffer != null) datagramLen =   
  8. DatagramBuffer.Length;  
  9.  
  10. // 调整长度(DataBuffer 为 null 不会出错)  
  11. Array.Resize(ref DatagramBuffer,   
  12. datagramLen + packLen);  
  13.  
  14. // 拷贝到数据就缓冲区  
  15. Array.Copy(ReceiveBuffer, startPos,   
  16. DatagramBuffer, datagramLen, packLen);  
  17. }  

代码中注释比较详细了,下面指出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通信三大问题有所帮助。

【编辑推荐】

  1. C#异步方法和同步方法的差异浅谈
  2. FlyTcpFramework在C#异步中的应用
  3. C#异步调用的应用实践浅谈
  4. 委托实现C#异步调用浅析
  5. 浅析C#中异步和多线程的区别
责任编辑:仲衡 来源: 博客园
相关推荐

2009-08-25 17:24:55

C#串口通信程序

2011-06-13 10:05:31

Android

2009-08-20 16:33:44

Socket异步通讯

2014-09-01 15:27:48

FTTH

2012-02-02 14:34:37

C# Socket

2009-06-05 11:07:30

2011-10-18 10:36:13

云计算云存储

2010-01-11 10:48:15

2009-08-28 11:43:26

C#数组初始化

2009-08-27 17:14:36

C# Socket

2015-11-05 11:20:14

2009-08-03 16:45:02

C#异步Socket

2009-08-18 16:45:40

C# Raw Sock

2021-09-13 22:31:24

人工智能疫情技术

2012-09-20 14:58:47

2022-06-21 13:48:30

Redis缓存

2021-03-10 13:53:53

5G运营商基站

2023-08-29 07:18:29

AMDN卡FSR 3

2009-09-15 10:46:06

Visual Stud

2011-05-19 14:16:29

网页设计
点赞
收藏

51CTO技术栈公众号