异步tcp通信——APM.Core 解包
TCP通信解包
虽说这是一个老生长谈的问题,不过网上基本很少见完整业务;或多或少都没有写完或者存在bug。接收到的数据包可以简单分成:小包、大包、跨包三种情况,根据这三种情况作相对应的拆包处理,示例如下:
/*****************************************************************************************************
* 本代码版权归@wenli所有,All Rights Reserved (C) 2015-2016
*****************************************************************************************************
* CLR版本:4.0.30319.42000
* 唯一标识:7a846c42-665d-4628-b91f-9d58b670437d
* 机器名称:WENLI-PC
* 联系人邮箱:wenguoli_520@qq.com
*****************************************************************************************************
* 项目名称:$projectname$
* 命名空间:APM.Core
* 类名称:UserToken
* 创建时间:2016/11/30 16:56:29
* 创建人:wenli
* 创建说明:
*****************************************************************************************************/
using System;
using System.Net.Sockets; namespace APM.Core
{
/// <summary>
/// tcp用户信息
/// </summary>
public class UserToken
{
private int offset, count = ; private byte[] _myBuffer; private byte[] _myLenBuffer; public int MaxBufferSize
{
get; private set;
} /// <summary>
/// 用户标识
/// </summary>
public string ID
{
get; set;
}
/// <summary>
/// 连接的客户
/// </summary>
public Socket Client
{
get; set;
} /// <summary>
/// 会话验证码
/// </summary>
public int Auth
{
get; set;
} public UserToken(int maxBufferSize = * )
{
this.MaxBufferSize = maxBufferSize;
this.ReceiveBuffer = new byte[this.MaxBufferSize];
} /// <summary>
/// 处理收取数据
/// 解包
/// </summary>
/// <param name="receiveData"></param>
/// <param name="action"></param>
internal void UnPackage(byte[] receiveData, Action<TcpPackage> action)
{
//当前包取内容的
if (offset == )
{
var packageLength = ;
if (this._myLenBuffer != null) //长度不完整的(包头不完整的)
{
//调整receiveData包内容
var nData = new byte[this._myLenBuffer.Length + receiveData.Length];
Buffer.BlockCopy(this._myLenBuffer, , nData, , this._myLenBuffer.Length);
Buffer.BlockCopy(receiveData, , nData, this._myLenBuffer.Length, receiveData.Length);
receiveData = nData;
nData = null;
this._myLenBuffer = null;
}
else //全新包(包头完整的)
{
packageLength = TcpPackage.GetLength(receiveData);
if (packageLength == )
return;
}
if (packageLength < receiveData.Length)
{
var package = TcpPackage.Parse(receiveData);
if (action != null && package != null)
{
action(package);
} var slen = TcpPackage.GetLength(receiveData, package.Length);
if (slen >= )
{
var next = new byte[receiveData.Length - package.Length];
Buffer.BlockCopy(receiveData, package.Length, next, , next.Length);
this.UnPackage(next, action);
}
}
else if (packageLength == receiveData.Length)
{
var package = TcpPackage.Parse(receiveData);
if (action != null && package != null)
{
action(package);
}
}
else if (packageLength > receiveData.Length)
{
this.count = packageLength;
this._myBuffer = new byte[packageLength];
Buffer.BlockCopy(receiveData, , this._myBuffer, , receiveData.Length);
this.offset = receiveData.Length;
}
receiveData = null; }
else //跨包取内容的
{
if (receiveData.Length + offset < count) //包内容超出
{
Buffer.BlockCopy(receiveData, , this._myBuffer, offset, receiveData.Length);
offset += receiveData.Length;
}
else if (receiveData.Length + offset >= count) //包内容短的
{
var packageLast = count - offset;
Buffer.BlockCopy(receiveData, , this._myBuffer, offset, packageLast);
var package = TcpPackage.Parse(this._myBuffer);
if (action != null && package != null)
{
action(package);
}
this._myBuffer = null;
count = offset = ;
var receiveLast = receiveData.Length - packageLast;
if (receiveLast >= )//包含包头长度
{
var packageLength = TcpPackage.GetLength(receiveData, packageLast);
if (packageLength > )
{
if (receiveLast > packageLength)
{
var nextData = new byte[receiveLast];
Buffer.BlockCopy(receiveData, packageLast, nextData, , receiveLast);
this.UnPackage(nextData, action);
}
else
{
this._myBuffer = new byte[packageLength];
Buffer.BlockCopy(receiveData, packageLast, this._myBuffer, , receiveLast);
offset = receiveLast;
count = packageLength;
}
}
else
{
this._myBuffer = null;
count = offset = ;
this._myLenBuffer = null;
}
}
else if (receiveLast > )//不包含包头长度
{
this._myLenBuffer = new byte[receiveLast];
Buffer.BlockCopy(receiveData, packageLast, this._myLenBuffer, , receiveLast);
if (TcpPackage.GetLength(this._myLenBuffer) == )
{
this._myLenBuffer = null;
}
this._myBuffer = null;
count = offset = ;
}
}
receiveData = null;
}
} public byte[] ReceiveBuffer
{
get; set;
} public void ClearReceiveBuffer()
{
for (int i = ; i < this.ReceiveBuffer.Length; i++)
{
this.ReceiveBuffer[i] = ;
}
}
}
}
有了解包就可以发超长消息、文件等
异步tcp通信——APM.Core 服务端概述
异步tcp通信——APM.Core 解包
异步tcp通信——APM.Server 消息推送服务的实现
异步tcp通信——APM.ConsoleDemo
转载请标明本文来源:http://www.cnblogs.com/yswenli/
更多内容欢迎star作者的github:https://github.com/yswenli/APM
如果发现本文有什么问题和任何建议,也随时欢迎交流~
异步tcp通信——APM.Core 解包的更多相关文章
- 异步tcp通信——APM.Core 服务端概述
为什么使用异步 异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池.就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理.异步操作执行时,会将操作丢给 ...
- 异步tcp通信——APM.Server 消息推送服务的实现
消息推送服务 服务器推送目前流行就是私信.发布/订阅等模式,基本上都是基于会话映射,消息对列等技术实现的:高性能.分布式可以如下解决:会话映射可采用redis cluster等技术实现,消息对列可使用 ...
- 异步tcp通信——APM.ConsoleDemo
APM测试 俗话说麻雀虽小,五脏俱全.apm虽然简单,但是可以实现单机高性能消息推送(可以采用redis.kafka等改造成大型分布式消息推送服务器). 测试demo: using System; u ...
- TCP、UDP详解与抓包工具使用
参考:https://www.cnblogs.com/HPAHPA/p/7737641.html TCP.UDP详解 1.传输层存在的必要性 由于网络层的分组传输是不可靠的,无法了解数据到达终点的时间 ...
- TCP通信丢包原因总结
今天在公司问老大,公司的项目底层,是使用的TCP,因为可靠,自动断线重连,在底层都实现了,但是我记得TCP也会有掉包的问题,所以这文章就诞生了——关于TCP掉包的问题,TCP是基于不可靠的网络实现可靠 ...
- TCP封包解包---如有错误,请纠正!
最近遇见很多的关于TCP中封包解包的数据,在TCP节点之间的信息传递,每次传送的内容是结构体,所以每次在传送的时候,要将结构体中的数据进行封包,然后当一端接收到数据之后,要对接收到的buf参数中的数据 ...
- TCP通信粘包问题分析和解决(全)(转)
TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送 ...
- 用Go实现的简易TCP通信框架
接触到GO之后,GO的网络支持非常令人喜欢.GO实现了在语法层面上可以保持同步语义,但是却又没有牺牲太多性能,底层一样使用了IO路径复用,比如在LINUX下用了EPOLL,在WINDOWS下用了IOC ...
- C# TCP socket发送大数据包时,接收端和发送端数据不一致 服务端接收Receive不完全
简单的c# TCP通讯(TcpListener) C# 的TCP Socket (同步方式) C# 的TCP Socket (异步方式) C# 的tcp Socket设置自定义超时时间 C# TCP ...
随机推荐
- 跟我学android-Activity介绍
Activity是android四大组件之一,activity 可以看成是一个屏幕,用户可以在这里做一些操作.activity通常都是满屏的,但也可以小于屏幕而浮于其它窗口之上,比如把activity ...
- linux makefle学习
学习材料取之这个网址:http://blog.chinaunix.net/uid-27717694-id-3696246.html 学习环境:ubuntu10.04-64bit-desktop版,gc ...
- Xshell下漂亮的开发环境配置
今天折腾了一天Xshell配置Linux命令行开发环境. 总结几点: 1.Xshell配色方案,这是我自己调的个人使用版,网上比较好的版本有Solarized Dark,可以下载到. [ColorFo ...
- 在Linux-0.11中实现基于内核栈切换的进程切换
原有的基于TSS的任务切换的不足 进程切换的六段论 1 中断进入内核 2 找到当前进程的PCB和新进程的PCB 3 完成PCB的切换 4 根据PCB完成内核栈的切换 5 切换运行资源LDT 6 利用I ...
- Android学习----ADB
adb是什么?:adb的全称为Android Debug Bridge,就是起到调试桥的作用.通过adb我们可以在Eclipse中方面通过DDMS来调试Android程序,说白了就是debug工具.a ...
- 我的vimrc配置
fankcoder@fankcoder:~$ cat ~/.vimrclet Tlist_Auto_Highlight_Tag=1 let Tlist_Auto_Open=1 let Tlist_Au ...
- ueditor 1.4.3.2 独立/单独 上传图片框原理
其实简单的说就是编辑框很多按钮,所有按钮的功能都是以command形式提供,所以execCommand就是执行这些功能的命令.有些按钮是能弹出显示一个对话框,他的基类就是dialog,而所有被弹出的d ...
- js 刷新页面大全
一.先来看一个简单的例子: 下面以三个页面分别命名为frame.html.top.html.bottom.html为例来具体说明如何做. frame.html 由上(top.html)下(bottom ...
- iOS开发——OC篇&消息传递机制(KVO/NOtification/Block/代理/Target-Action)
iOS开发中消息传递机制(KVO/NOtification/Block/代理/Target-Action) 今晚看到了一篇好的文章,所以就搬过来了,方便自己以后学习 虽然这一期的主题是关于Fou ...
- (转)JavaScript 开发者经常忽略或误用的七个基础知识点
英文原文:7 JavaScript Basics Many Developers Aren't Using (Properly) JavaScript 本身可以算是一门简单的语言,但我们也不断用智慧和 ...