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
如果发现本文有什么问题和任何建议,也随时欢迎交流~