高性能TcpServer(C#) - 1.网络通信协议

高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)

高性能TcpServer(C#) - 3.命令通道(处理:掉包,粘包,垃圾包)

高性能TcpServer(C#) - 4.文件通道(处理:文件分包,支持断点续传)

高性能TcpServer(C#) - 5.客户端管理

高性能TcpServer(C#) - 6.代码下载

处理原理

每个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.命令通道(处理:掉包,粘包,垃圾包)的更多相关文章

  1. 高性能TcpServer(C#) - 4.文件通道(处理:文件分包,支持断点续传)

    高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...

  2. C#高性能大容量SOCKET并发(五):粘包、分包、解包

    原文:C#高性能大容量SOCKET并发(五):粘包.分包.解包 粘包 使用TCP长连接就会引入粘包的问题,粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一 ...

  3. DELPHI高性能大容量SOCKET并发(四):粘包、分包、解包

    粘包 使用TCP长连接就会引入粘包的问题,粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.粘包可能由发送方造成,也可能由接收方造成.TCP为提 ...

  4. 高性能TcpServer(C#) - 1.网络通信协议

    高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...

  5. 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)

    高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...

  6. 高性能TcpServer(C#) - 5.客户端管理

    高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...

  7. 高性能TcpServer(C#) - 6.代码下载

    高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...

  8. 高性能TcpServer(Java) - Netty

    源码下载 -> 提取码  QQ:505645074 Netty 是一个高性能.异步事件驱动的 NIO 框架,它提供了对 TCP.UDP 和文件传输的支持,作为一个异步 NIO 框架,Netty ...

  9. 网络编程之模拟ssh远程执行命令、粘包问题 、解决粘包问题

    目录 模拟ssh远程执行命令 服务端 客户端 粘包问题 什么是粘包 TCP发送数据的四种情况 粘包的两种情况 解决粘包问题 struct模块 解决粘包问题 服务端 客户端 模拟ssh远程执行命令 服务 ...

随机推荐

  1. java基础(14):Eclipse、面向对象、自定义数据类型的使用

    1. Eclipse的应用 1. 常用快捷操作 Ctrl+T:查看所选中类的继承树 例如,在下面代码中,选中Teacher类名,然后按Ctrl+T,就会显示出Teacher类的继承关系 //员工 ab ...

  2. 我用python爬取了知乎Top沙雕问题排行榜

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 数据森麟 PS:如有需要Python学习资料的小伙伴可以加点击下方 ...

  3. 机器学习实战:基于Scikit-Learn和TensorFlow 读书笔记 第6章 决策树

    数据挖掘作业,要实现决策树,现记录学习过程 win10系统,Python 3.7.0 构建一个决策树,在鸢尾花数据集上训练一个DecisionTreeClassifier: from sklearn. ...

  4. 如何通过纯javascript实现表单提交

    通常,如果是POST方法,一般使用vuejs+axios,或使用Jquery实现表单提交.有些地方,我想使用纯JS实现,比方简单的登陆跳转.话不多说,看原代码, laravel中的HTML部分,如果不 ...

  5. Dynamics CRM定制子网格添加按钮实例之一

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复221或者20160430可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  6. Gatech OMSCS的申请和学习之奥妙

    https://zhuanlan.zhihu.com/p/54680585 我写东西一向希望能给大家带来正能量,提供有价值的信息,不辱没母校的厚德价值观. 我是传统没落工科毕业后开发软件,但是一直没下 ...

  7. [20191002]函数dump的bug.txt

    [20191002]函数dump的bug.txt --//前几天写raw转化oracle number脚本,在使用函数dump时遇到一些问题,做一个记录:--//oracle number 0 编码 ...

  8. nginx 的 proxy_cache 缓存配置

    开头:某个项目涉及到 视频切片下载到本地,然后提供服务给客户端.一个视频有多个文件,存储在本地路径下.当客户端请求的视频在本地没有就会回源, 回源拿到的视频文件再返回给客户端,同时在本地缓存一份,提供 ...

  9. 线性回归——lasso回归和岭回归(ridge regression)

    目录 线性回归--最小二乘 Lasso回归和岭回归 为什么 lasso 更容易使部分权重变为 0 而 ridge 不行? References 线性回归很简单,用线性函数拟合数据,用 mean squ ...

  10. Pwnable-mistake

    先看看c的源码 #include <stdio.h> #include <fcntl.h> #define PW_LEN 10 #define XORKEY 1 void xo ...