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

高性能TcpServer - 1.网络通信协议

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

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

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

高性能TcpServer - 5.客户端管理

高性能TcpServer - 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#[email protected][email protected][email protected]=2018-02-05 17:36:[email protected][{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 = "[email protected]" + 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 = "[email protected]" + softtype + " 第" + downindex + "包的数据为空";

else

analysis.Msg = filedata;

}

}

}

break;

case 7:

// 更新版本信息(update sql)

analysis.Msg = "ok";

break;

}

}

catch (Exception ex)

{

analysis.Msg = "[email protected]" + 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

时间: 2024-08-01 05:23:54

高性能TcpServer - 3.命令通道(处理:掉包,粘包,垃圾包)的相关文章

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

高性能TcpServer - 1.网络通信协议 高性能TcpServer - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpServer - 3.命令通道(处理:掉包,粘包,垃圾包) 高性能TcpServer - 4.文件通道(处理:文件分包,支持断点续传) 高性能TcpServer - 5.客户端管理 高性能TcpServer - 6.代码下载 应用场景: 升级程序 流程:终端->查询服务器版本比较->升级程序(获取包数,获取各包数据

高性能TcpServer&#160;-&#160;5.客户端管理

高性能TcpServer - 1.网络通信协议 高性能TcpServer - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpServer - 3.命令通道(处理:掉包,粘包,垃圾包) 高性能TcpServer - 4.文件通道(处理:文件分包,支持断点续传) 高性能TcpServer - 5.客户端管理 高性能TcpServer - 6.代码下载 链路清理 1. 客户端主动断开连接(socket能侦测到) 2.未知原因导致连接中断(拔网线

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

DELPHI高性能大容量SOCKET并发(四):粘包.分包.解包 粘包 使用TCP长连接就会引入粘包的问题,粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.粘包可能由发送方造成,也可能由接收方造成.TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据,造成多个数据包的粘连.如果接收进程不及时接收数据,已收到的数据就放在系统接收缓冲区,用户进程读取数据时就可能同时读到多个数据包. 粘包一般的解决办法是制定通讯协议,由协议来规

python 网络编程(远程执行命令与粘包)

远程执行命令 先来学习一个新模块 , 一会用到的.. 新模块: subprocess 执行系统命令 r = subprocess.Popen('ls',shell=True,stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.Popen(a,b,c,d) a: 要执行的系统命令(str) b: shell = True 表示确定我当前执行的命令为系统命令 c: 表示正确信息的输出管道 d: 表示错误信息的输出管道 下边直接上代码,

粘包产生的原因 socket 基于tcp实现远程执行命令(解决粘包)low

# 粘包产生的原因 # 粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的. # 基于tcp协议的套接字会有粘包现象,而基于udp协议的套接字不会产生粘包现象 # tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住:而udp是基于数据报的,即使你输入的是空内容,那也不是空消息,udp协议会帮你封装上消息头(ip+端口的方式),这样就有了消息办界 # 两种情况下会发生粘包 # 1.发送端需要等缓冲区满才发送

关于TCP封包、粘包、半包

关于Tcp封包 很多朋友已经对此作了不少研究,也花费不少心血编写了实现代码和blog文档.当然也充斥着一些各式的评论,自己看了一下,总结一些心得. 首先我们学习一下这些朋友的心得,他们是: http://blog.csdn.net/stamhe/article/details/4569530 http://www.cppblog.com/tx7do/archive/2011/05/04/145699.html //……………… 当然还有太多,很多东西粘来粘区也不知道到底是谁的原作,J 看这些朋友

TCP 拆、粘包

Netty(三) 什么是 TCP 拆.粘包?如何解决? 前言 记得前段时间我们生产上的一个网关出现了故障. 这个网关逻辑非常简单,就是接收客户端的请求然后解析报文最后发送短信. 但这个请求并不是常见的 HTTP ,而是利用 Netty 自定义的协议. 有个前提是:网关是需要读取一段完整的报文才能进行后面的逻辑. 问题是有天突然发现网关解析报文出错,查看了客户端的发送日志也没发现问题,最后通过日志发现收到了许多不完整的报文,有些还多了. 于是想会不会是 TCP 拆.粘包带来的问题,最后利用 Net

scoket模块 粘包问题 tcp协议特点

scoket()模块函数用法 import socket socket.socket(socket_family,socket_type,protocal=0) 获取tcp/ip套接字 tcpsock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 获取udp/ip套接字 udpsock =socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 服务端套接字函数 s.bind()    绑定(主机,端口号)

python之网络编程粘包

一.粘包 粘包现象 # 服务端 import socket import subprocess phone = socket.socket() phone.bind(('127.0.0.1',8888)) phone.listen(5) while 1: conn,addr = phone.accept() while 1: cmd = conn.recv(1024) ret = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=s