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 解包的更多相关文章

  1. 异步tcp通信——APM.Core 服务端概述

    为什么使用异步 异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池.就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理.异步操作执行时,会将操作丢给 ...

  2. 异步tcp通信——APM.Server 消息推送服务的实现

    消息推送服务 服务器推送目前流行就是私信.发布/订阅等模式,基本上都是基于会话映射,消息对列等技术实现的:高性能.分布式可以如下解决:会话映射可采用redis cluster等技术实现,消息对列可使用 ...

  3. 异步tcp通信——APM.ConsoleDemo

    APM测试 俗话说麻雀虽小,五脏俱全.apm虽然简单,但是可以实现单机高性能消息推送(可以采用redis.kafka等改造成大型分布式消息推送服务器). 测试demo: using System; u ...

  4. TCP、UDP详解与抓包工具使用

    参考:https://www.cnblogs.com/HPAHPA/p/7737641.html TCP.UDP详解 1.传输层存在的必要性 由于网络层的分组传输是不可靠的,无法了解数据到达终点的时间 ...

  5. TCP通信丢包原因总结

    今天在公司问老大,公司的项目底层,是使用的TCP,因为可靠,自动断线重连,在底层都实现了,但是我记得TCP也会有掉包的问题,所以这文章就诞生了——关于TCP掉包的问题,TCP是基于不可靠的网络实现可靠 ...

  6. TCP封包解包---如有错误,请纠正!

    最近遇见很多的关于TCP中封包解包的数据,在TCP节点之间的信息传递,每次传送的内容是结构体,所以每次在传送的时候,要将结构体中的数据进行封包,然后当一端接收到数据之后,要对接收到的buf参数中的数据 ...

  7. TCP通信粘包问题分析和解决(全)(转)

    TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送 ...

  8. 用Go实现的简易TCP通信框架

    接触到GO之后,GO的网络支持非常令人喜欢.GO实现了在语法层面上可以保持同步语义,但是却又没有牺牲太多性能,底层一样使用了IO路径复用,比如在LINUX下用了EPOLL,在WINDOWS下用了IOC ...

  9. C# TCP socket发送大数据包时,接收端和发送端数据不一致 服务端接收Receive不完全

    简单的c# TCP通讯(TcpListener) C# 的TCP Socket (同步方式) C# 的TCP Socket (异步方式) C# 的tcp Socket设置自定义超时时间 C# TCP ...

随机推荐

  1. 『重构--改善既有代码的设计』读书笔记----Extract Method

    在编程中,比较忌讳的一件事情就是长函数.因为长函数代表了你这段代码不能很好的复用以及内部可能出现很多别的地方的重复代码,而且这段长函数内部的处理逻辑你也不能很好的看清楚.因此,今天重构第一个手法就是处 ...

  2. Python几种创建list的方法的效率对比

    我们用 生成一个0到((1万倍n)-1)的list做例子 首先这种方式复杂度为平方级 ''' def test1(n): lst = [] for i in range(n*10000): lst = ...

  3. MLlib-聚类

    聚类 例子 流聚类 例子 聚类 MLlib支持k-means聚类,一种最常用的聚类方法,将数据点聚成指定数据的簇.MLlib实现了一种k-means++的并行变种,叫做kmeansII.MLlib的实 ...

  4. debian小巧好看的桌面

    先看完,不然,你一定会后悔的..不好看,你打我.. sudo apt-get install xfce4 sudo apt-get install xfce4-goodies sudo apt-get ...

  5. 如何改变dreamweaver的编码方式

  6. 将MYSQL查询导出到文件

    sql文件: set names utf8; select * from xxxxx mysql命令: mysql .sql .txt

  7. Google 高性能 RPC 框架 gRPC 1.0.0 发布(附精彩评论)

    gRPC是一个高性能.开源.通用的RPC框架,面向移动和HTTP/2设计,是由谷歌发布的首款基于Protocol Buffers的RPC框架. gRPC基于HTTP/2标准设计,带来诸如双向流.流控. ...

  8. 【HDOJ】2809 God of War

    状态DP. /* 2809 */ #include <iostream> #include <queue> #include <cstdio> #include & ...

  9. HttpURLConnection和HttpClient

    HTTP 协议可能是现在 Internet 上使用得最多.最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源.在 JDK 的 java.net 包中已经提供了访问 ...

  10. LeetCode——Remove Duplicates from Sorted Array

    Given a sorted array, remove the duplicates in place such that each element appear only once and ret ...