C# Socket通讯常见问题详解通讯常见问题详解
C# Socket通信三大问题之数据包界限符问题。
根据原项目中交通部标准,在连续观测站中数据包中,使用??两个字符表示有效数据包开始和结束。实际项目有各自的
具体技术规范
C# Socket通信三大问题之数据包不连续问题。
在TCP/IP等通信中,由于时延等原因,一个数据包被Socket做两次或多次接收,此时在接收第一个包后,必须保存到
TSession的DatagramBuffer中,在以后一并处理
C# Socket通信三大问题包并发与重叠问题。
由于客户端发送过快或设备故障等原因,一次接收到一个半、两个或多个包文。此时,也需要处理、一个半、两个或多个
包
先补充异步BeginReceive()回调函数EndReceiveData()中的数据包分合函数ResolveBuffer()。
下面是C# Socket通信三大问题的实例演示:
/// ?summary?
/// 1) 报文界限字符为??,其它为合法字符,
/// 2) 按报文头、界限标志抽取报文,可能合并包文
/// 3) 如果一次收完数据,此时 DatagramBuffer 为空
/// 4) 否则转存到包文缓冲区 session.DatagramBuffer
/// ?/summary?
private void ResolveBuffer(TSession session, int receivedSize)
{
// 上次留下的报文缓冲区非空(注意:必然含有开始字符 ?,空时不含 ?)
bool hasBeginChar = (session.DatagramBufferLength ? 0);
int packPos = 0; // ReceiveBuffer 缓冲区中包的开始位置
int packLen = 0; // 已经解析的接收缓冲区大小
byte dataByte = 0; // 缓冲区字节
int subIndex = 0; // 缓冲区下标
while (subIndex ? receivedSize)
{
// 接收缓冲区数据,要与报文缓冲区 session.DatagramBuffer 同时考虑
dataByte = session.ReceiveBuffer[subIndex];
if (dataByte == TDatagram.BeginChar) // 是数据包的开始字符?,则前面的包文均要放弃
{
// ?前面有非空串(包括报文缓冲区),则前面是错包文,防止 AAA?A,1,A? 两个报文一次读现象
if (packLen ? 0)
{
Interlocked.Increment( ref _datagramCount); // 前面有非空字符
Interlocked.Increment( ref _errorDatagramCount); // 一个错误包
this .OnDatagramError();
}
session.ClearDatagramBuffer(); // 清空会话缓冲区,开始一个新包
packPos = subIndex; // 新包起点,即?所在位置
packLen = 1; // 新包的长度(即?)
hasBeginChar = true ; // 新包有开始字符
}
else if (dataByte == TDatagram.EndChar) // 数据包的结束字符 ?
{
if (hasBeginChar) // 两个缓冲区中有开始字符?
{
++packLen; // 长度包括结束字符?
// ?前面的为正确格式的包,则分析该包,并准备加入包队列
AnalyzeOneDatagram(session, packPos, packLen);
packPos = subIndex + 1; // 新包起点。注意:subIndex 在循环后处 + 1
packLen = 0; // 新包长度
}
else // ?前面没有开始字符,则认为结束字符?为一般字符,待后续的错误包处理
{
++packLen; // hasBeginChar = false;
}
}
else // 非界限字符??,是是一般字符,长度 + 1,待解析包处理
{
++packLen;
}
++subIndex; // 增加下标号
} // end while
if (packLen ? 0) // 剩下的待处理串,分两种情况
评论0