高性能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##

转载于:https://www.cnblogs.com/chen1880/p/11238699.html

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

  1. cmd库的导入Java,在cmd命令窗口导入第三方jar包来运行java文件

    在cmd命令窗口导入第三方jar包来运行java文件,以下测试都是基于window环境,Linux环境没有测试. 1.编译 使用命令javac -cp或者javac -classpath 本机测试:如 ...

  2. 【Java】命令行下的Java包结构编译与执行

    编写代码 com.hhh.test.PackageTest package com.hhh.test;public class PackageTest {public static void main ...

  3. adb命令行刷机 使用adb sideload命令推送刷机包到recovery直接刷机

    还在烦恼复制黏贴刷机包到手机内存里的烦恼吗?还在烦恼USB挂载无法移动的烦恼吗?使用adb sideload命令推送刷机包到recovery直接刷机.就算你的手机无法进入系统或者已经崩溃了使用ADB命 ...

  4. 02Tcpdump命令详解-网络抓包工具

    1.概述 今天我们要介绍的是一款网络抓包工具tcpdump,重点讨论并介绍一些有用的命令及最佳实践. tcpdump是一个功能最强大,应用最广泛的命令行数据包嗅探器或包分析工具,用于抓取或过滤制定接口 ...

  5. dnf命令参数详细说明、bclinux8或centos8以上系统使用dnf命令离线安装本地rpm包方法及场景和原因、使用dnf命令提示正在等待 pid 为422620的进程退出。的解决方法

    文章目录 dnf命令 dnf说明 安装 DNF 包管理器 dnf [选项] 命令 [dnf使用说明] dnf安装本地rpm包 全部参数 bclinux8或centos8以上系统使用dnf命令安装rpm ...

  6. linux移除包的命令,linux的yum卸载包命令说明

    Linux中的yum命令可以通过相关命令对包进行安装.卸载或者更新等,下面由学习啦小编为大家整理了Linux的yum卸载包命令说明的相关知识,希望对大家有帮助! linux的yum卸载包命令说明 1& ...

  7. 【计算机网络】 0、各网络命令 + tcpdump + Wireshark、抓包实战、TCP 握手挥手、防火墙、保活、MTU

    文章目录 一.各层网络工具 应用层 找到服务器的 IP 查接口.对象的耗时 删除指定网站的Cookie 表示层.会话层 tcpdump.wireshard 传输层 telnet: 路径可达性测试 nc ...

  8. linux 网络命令查看流量、抓包

    dstat linux查看流量 dstat命令是一个用来替换vmstat.iostat.netstat.nfsstat和ifstat这些命令的工具,是一个全能系统信息统计工具.与sysstat相比,d ...

  9. 使用jar命令查看搜索提取jar包中的文件

    查看jar包的目录结构:jar ftv xxx.jar 带ftv三个参数: 根据资料,查找jar包中yyy.xml文件的命令是:jar ftv xxx.jar |grep yyy.xml: 命令出错: ...

最新文章

  1. 关于CLSCompliant
  2. Understand分析Kinect SDK 1.7自带例子(C++)图集一
  3. 安装和使用Oracle Instant Client 和 SQLPlus
  4. linux-shell命令之rm(remove)【删除文件或目录】
  5. HALCON示例程序distance_transform.hdev通过distance_transform检测线的缺陷
  6. 如何备份 Outlook Express 项
  7. robotFramework-ride使用2-分支与循环
  8. 关于数据库中的锁,你不知道的是...
  9. 蔚来发布首款自动驾驶车型ET7 补贴前起售价44.8万元
  10. python数字和运算符空格_Python基础——运算符与数据结构(200315)
  11. 狸猫换太子--删除无头单链表中结点
  12. SQL Server MYSQL 对外键建立索引的必要性
  13. html+css+js制作LOL官网,web前端大作业(3个页面+模拟登录+链接)
  14. 视频教程-2020年软考网络工程师基础知识软考视频教程-软考
  15. vue中对鼠标划过事件处理方式
  16. word排版遇到的问题
  17. 20sccm_SCCM 2016 使用PXE 部署操作系统(一)
  18. 电脑不用下软件开wifi
  19. ubuntu安装sdkman
  20. VS2010 提示存储空间不足 无法操作

热门文章

  1. 聊聊运营活动的设计与实现逻辑
  2. 用Shell脚本实现自动从NewSmth.net的MyPhoto版下载照片
  3. 这个表是怎么回事??? [问题点数:50分] 收藏
  4. 如果编程语言是一门武功绝学!那你学什么,才会成为天下第一?
  5. Android Service完全解析,关于服务你所需知道的一切(上)
  6. 本人从事Java十余年~是时候收徒弟~包教包会~深藏功与名~
  7. 晶体管问世;科幻巨匠诞生 | 历史上的今天
  8. python加换行和去换行(去掉换行,end =““;加换行 ,‘/n‘)
  9. 985高校大数据专业教学究竟怎么样?在校生有话说
  10. Python等级考试一道关于血压的综合题解析