高性能TcpServer(C#) - 3.命令通道(处理:掉包,粘包,垃圾包)
高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)
高性能TcpServer(C#) - 3.命令通道(处理:掉包,粘包,垃圾包)
高性能TcpServer(C#) - 4.文件通道(处理:文件分包,支持断点续传)
处理原理:
每个client创建各自的byte[]数组,通过遍历每个字节的数据
1.判断包长,确定掉包;
2.判断解析完后byte数组是否还有未解析的数据,确定粘包;
3.判断包头,确定垃圾包;
缓存数据类
/// <summary>
/// 缓存数据类
/// </summary>
public class CByteBuffer
{
// 默认1k
int m_iBufferSize = 1024 * 1;
// 数据解析
byte[] m_abyBuf;
int m_iPosition = 0;
int m_iRecvLength = 0;
bool bWaitRecvRemain;// 数据未接收完等待接收
object m_lock = new object(); // 内部同步锁
public int Position
{
get { return m_iPosition; }
set { m_iPosition = value; }
}
public int RecvLength
{
get { return m_iRecvLength; }
set { m_iRecvLength = value; }
}
public bool WaitRecvRemain
{
get { return bWaitRecvRemain; }
set { bWaitRecvRemain = value; }
}
public CByteBuffer(int buffSize)
{
m_iBufferSize = buffSize;
m_abyBuf = new byte[m_iBufferSize];
}
public int GetPosition()
{
return m_iPosition;
}
public int GetRecvLength()
{
return m_iRecvLength;
}
public void Put(SocketAsyncEventArgs e)
{
int iLength = e.BytesTransferred;
if (m_iRecvLength + iLength >= m_iBufferSize)
{
Clear();
return;
}
lock (m_lock)
{
Array.Copy(e.Buffer, e.Offset, m_abyBuf, m_iRecvLength, iLength);
m_iRecvLength += iLength;
}
}
public byte GetByte()
{
bWaitRecvRemain = false;
if (m_iPosition >= m_iRecvLength)
{
bWaitRecvRemain = true;
return 0;
}
byte byRet;
lock (m_lock)
{
byRet = m_abyBuf[m_iPosition];
}
m_iPosition++;
return byRet;
}
public byte[] GetByteArray(int Length)
{
bWaitRecvRemain = false;
if (m_iPosition + Length > m_iRecvLength)
{
bWaitRecvRemain = true;
return null;
}
byte[] ret = new byte[Length];
lock (m_lock)
{
Array.Copy(m_abyBuf, m_iPosition, ret, 0, Length);
m_iPosition += Length;
}
return ret;
}
public bool HasRemaining()
{
return m_iPosition < m_iRecvLength;
}
public int Remaining()
{
return m_iRecvLength - m_iPosition;
}
public void Clear()
{
m_iPosition = 0;
m_iRecvLength = 0;
bWaitRecvRemain = false;
}
~CByteBuffer()
{
m_abyBuf = null;
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
GC.SuppressFinalize(this);
}
}
public void Dispose()
{
Dispose(true);
}
}
协议解析类
public void Process(CByteBuffer bBuffer, CProtocolAnalysis analysis, string sn)
{
analysis.BagStatus = CProtocolAnalysis.EBagStatus.BagNone;
analysis.WhetherToSend = false;
int iPosition = bBuffer.Position;
byte head1 = 0; byte head2 = 0; byte head3 = 0; byte head4 = 0; byte head5 = 0; byte head6 = 0; bool headok = false;
if (!bBuffer.HasRemaining()) return;
while (bBuffer.HasRemaining())
{
head1 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;
if (HEAD1 == head1)
{
iPosition = bBuffer.Position - 1;
head2 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;
head3 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;
head4 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;
head5 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;
head6 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;
if (HEAD2 == head2 && HEAD3 == head3 && HEAD4 == head4 && HEAD5 == head5 && HEAD6 == head6)
{
headok = true;
break;
}
else
{
CLogHelp.AppendLog("Error,Unable to parse the data2:Position=" + iPosition.ToString() + ",Index=" + (bBuffer.GetPosition()).ToString() + ",Head2=" + head2.ToString());
}
}
else
{
CLogHelp.AppendLog("Error,Unable to parse the data1:Position=" + iPosition.ToString() + ",Index=" + (bBuffer.GetPosition()).ToString() + ",Head1=" + head1.ToString());
}
}
if (!bBuffer.HasRemaining())
{
if (headok)
{
if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;
}
return;
}
byte[] arrlen = bBuffer.GetByteArray(4); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;
int len = CCommonFunc.String2Int(CCommonFunc.ByteToString(arrlen)); if (-1 == len) return;
byte[] source = bBuffer.GetByteArray(len); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;
if (!bBuffer.HasRemaining())
{
bBuffer.Clear();
}
else
{
analysis.BagStatus = CProtocolAnalysis.EBagStatus.BagStick;
}
// #WaterMeter-001#01##
string data = CCommonFunc.ByteToString(source);
if (null == data || 0 == data.Length || data.Length - 1 != data.LastIndexOf(SPLIT1))
{
return;
}
data = data.Substring(1, data.Length - 2);
string[] item = data.Split(SPLIT1);
if (null == item || 4 != item.Length)
{
return;
}
string uid = item[0];
string taskid = item[1];
int cmd = CCommonFunc.String2Int(item[2]);
string content = item[3];
Program.AddMessage("R: [" + sn + "] cmd=" + cmd.ToString() + " data=" + data);
analysis.Cmd = cmd;
analysis.Uid = uid;
analysis.TaskId = taskid;
if (cmd == 1 || cmd == 2 || cmd == 3 || cmd == 4 || cmd == 5 || cmd == 6 || cmd == 7)
{
analysis.WhetherToSend = true;
}
string softtype = "";
try
{
switch (cmd)
{
case 1:
analysis.Msg = "ok";
break;
case 2:
analysis.Msg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
break;
case 3:
// HTEMP=0263#WaterMeter-001#1520557004#03#buildid=44@edmid=37@meterid=1228@senddate=2018-02-05 17:36:22@[{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}]#
analysis.Msg = "ok";
break;
case 4:
{
// 获取版本信息
softtype = content.Split(SPLIT2)[1];
StorageFile(softtype, System.Windows.Forms.Application.StartupPath + "\\test.zip");
analysis.Msg = "2";// version
}
break;
case 5:
// 获取包数
{
softtype = content.Split(SPLIT2)[1];
if (!dicSoft.ContainsKey(softtype))
{
StorageFile(softtype, System.Windows.Forms.Application.StartupPath + "\\test.zip");
}
// 获取包数
int count = 0;
FileCut entity = null;
dicSoft.TryGetValue(softtype, out entity);
if (null != entity) count = entity.Count;
analysis.Msg = count.ToString();
}
break;
case 6:
// 执行更新动作
{
string[] items = content.Split(SPLIT2);
softtype = items[1];
int downindex = CCommonFunc.String2Int(items[2]);
if (!dicSoft.ContainsKey(softtype))
{
analysis.Msg = "error@" + softtype + " 未找到更新文件,请先获取包数";
}
else
{
FileCut entity = null;
dicSoft.TryGetValue(softtype, out entity);
if (null != entity)
{
string filedata = "";
entity.Data.TryGetValue(downindex, out filedata);
if (string.IsNullOrEmpty(filedata))
analysis.Msg = "error@" + softtype + " 第" + downindex + "包的数据为空";
else
analysis.Msg = filedata;
}
}
}
break;
case 7:
// 更新版本信息(update sql)
analysis.Msg = "ok";
break;
}
}
catch (Exception ex)
{
analysis.Msg = "error@" + ex.Message;
}
Program.AddMessage("S: [" + sn + "] cmd=" + cmd.ToString() + " data=" + analysis.Msg);
}
测试效果
正常包
HTEMP=0026#Meter-001#1533022506#01##

掉包(分两包发送)
HTEMP=0026#
Meter-001#1533022506#01##

粘包(两包一起发送)
HTEMP=0026#Meter-001#1533022506#01##HTEMP=0026#Meter-001#1533022506#01##

高性能TcpServer(C#) - 3.命令通道(处理:掉包,粘包,垃圾包)的更多相关文章
- 高性能TcpServer(C#) - 4.文件通道(处理:文件分包,支持断点续传)
高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...
- C#高性能大容量SOCKET并发(五):粘包、分包、解包
原文:C#高性能大容量SOCKET并发(五):粘包.分包.解包 粘包 使用TCP长连接就会引入粘包的问题,粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一 ...
- DELPHI高性能大容量SOCKET并发(四):粘包、分包、解包
粘包 使用TCP长连接就会引入粘包的问题,粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.粘包可能由发送方造成,也可能由接收方造成.TCP为提 ...
- 高性能TcpServer(C#) - 1.网络通信协议
高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...
- 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)
高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...
- 高性能TcpServer(C#) - 5.客户端管理
高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...
- 高性能TcpServer(C#) - 6.代码下载
高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...
- 高性能TcpServer(Java) - Netty
源码下载 -> 提取码 QQ:505645074 Netty 是一个高性能.异步事件驱动的 NIO 框架,它提供了对 TCP.UDP 和文件传输的支持,作为一个异步 NIO 框架,Netty ...
- 网络编程之模拟ssh远程执行命令、粘包问题 、解决粘包问题
目录 模拟ssh远程执行命令 服务端 客户端 粘包问题 什么是粘包 TCP发送数据的四种情况 粘包的两种情况 解决粘包问题 struct模块 解决粘包问题 服务端 客户端 模拟ssh远程执行命令 服务 ...
随机推荐
- java基础(16):正则表达式、Date、DateFormat、Calendar
1. 正则表达式 1.1 正则表达式的概念 正则表达式(英语:Regular Expression,在代码中常简写为regex). 正则表达式是一个字符串,使用单个字符串来描述.用来定义匹配规则,匹配 ...
- Java生鲜电商平台-OMS订单系统中并发问题和锁机制的探讨与解决方案
Java生鲜电商平台-OMS订单系统中并发问题和锁机制的探讨与解决方案 说明:Java开源生鲜电商中OMS订单系统中并发问题和锁机制的探讨与解决方案: 问题由来 假设在一个订单系统中(以火车票 ...
- Android框架之EventBus的使用
简介 EventBus是由greenrobot组织贡献的一个Android事件发布/订阅的轻量级框架.EventBus是一个Android端优化的publish/subscribe消息总线,简化了应用 ...
- 究竟是什么毁了我的impl实现
Impl模式早就有过接触(本文特指通过指针完成impl),我晓得它具有以下优点: 减少头文件暴露出来的非必要内部类(提供静态库,动态库时尤其重要): 减小文件间的编译依存关系,大型代码库的编译时间就不 ...
- Linux--简单实现nfs的目录挂载,ntp时间同步
一.NFS (Network FileSystem) 网络文件系统 是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源. 在NFS的应用中,本地NFS的客户端 ...
- c++ 多态的内幕
c++ 多态,就是利用了一个二级指针(指针数组),数组里的每个元素都指向了,用virtual修饰的成员函数. 既然提到了指针,那就让我们用内存地址来证明一下吧. 为了证明,我们必须要取到成员函数的首地 ...
- IAR调试查看程序时间
在无仿真器情况下设置: 调试仿真,点击view菜单下registers 软件仿真时计算两断点CYCLECOUNTER(在CPU registers中)的差值,乘以指令周期(MCLK)便是执行时间
- PHP 安装xdebug
xdebug官网: https://xdebug.org 安装步骤如下: 使用 phpinfo() 打印出PHP相关信息, 全选, 复制 打开 xdebug 网站: https://xdebug.or ...
- Html学习之十(CSS选择器的使用--伪类选择器)
伪类选择器 一.基于a标签. 1.:hover 选择鼠标滑过的超链接元素 2.:active 选择鼠标单击中的超链接元素 3.:link 选择未被访问的超链接元素 4.:visited 选择已经被访问 ...
- pycharm安装pymysql包
1.为什么? 每个程序连接数据库,python开发2.*版本可以直接使用MySQL,python3.*版本需要下载使用PyMySQL包才能连接数据库... 2. 怎么做? 2.1. 更改源:pycha ...