异步tcp通信——APM.Core 解包

TCP通信解包

  虽说这是一个老生长谈的问题,不过网上基本很少见完整业务;或多或少都没有写完或者存在bug。接收到的数据包可以简单分成:小包、大包、跨包三种情况,根据这三种情况作相对应的拆包处理,示例如下:

 

  1 /*****************************************************************************************************
  2  * 本代码版权归@wenli所有,All Rights Reserved (C) 2015-2016
  3  *****************************************************************************************************
  4  * CLR版本:4.0.30319.42000
  5  * 唯一标识:7a846c42-665d-4628-b91f-9d58b670437d
  6  * 机器名称:WENLI-PC
  7  * 联系人邮箱:wenguoli_520@qq.com
  8  *****************************************************************************************************
  9  * 项目名称:$projectname$
 10  * 命名空间:APM.Core
 11  * 类名称:UserToken
 12  * 创建时间:2016/11/30 16:56:29
 13  * 创建人:wenli
 14  * 创建说明:
 15  *****************************************************************************************************/
 16 using System;
 17 using System.Net.Sockets;
 18 
 19 namespace APM.Core
 20 {
 21     /// <summary>
 22     /// tcp用户信息
 23     /// </summary>
 24     public class UserToken
 25     {
 26         private int offset, count = 0;
 27 
 28         private byte[] _myBuffer;
 29 
 30         private byte[] _myLenBuffer;
 31 
 32         public int MaxBufferSize
 33         {
 34             get; private set;
 35         }
 36 
 37         /// <summary>
 38         /// 用户标识
 39         /// </summary>
 40         public string ID
 41         {
 42             get; set;
 43         }
 44         /// <summary>
 45         /// 连接的客户
 46         /// </summary>
 47         public Socket Client
 48         {
 49             get; set;
 50         }
 51 
 52         /// <summary>
 53         /// 会话验证码
 54         /// </summary>
 55         public int Auth
 56         {
 57             get; set;
 58         }
 59 
 60 
 61 
 62         public UserToken(int maxBufferSize = 10 * 1024)
 63         {
 64             this.MaxBufferSize = maxBufferSize;
 65             this.ReceiveBuffer = new byte[this.MaxBufferSize];
 66         }
 67 
 68 
 69 
 70         /// <summary>
 71         /// 处理收取数据
 72         /// 解包
 73         /// </summary>
 74         /// <param name="receiveData"></param>
 75         /// <param name="action"></param>
 76         internal void UnPackage(byte[] receiveData, Action<TcpPackage> action)
 77         {
 78             //当前包取内容的
 79             if (offset == 0)
 80             {
 81                 var packageLength = 0;
 82                 if (this._myLenBuffer != null) //长度不完整的(包头不完整的)
 83                 {
 84                     //调整receiveData包内容
 85                     var nData = new byte[this._myLenBuffer.Length + receiveData.Length];
 86                     Buffer.BlockCopy(this._myLenBuffer, 0, nData, 0, this._myLenBuffer.Length);
 87                     Buffer.BlockCopy(receiveData, 0, nData, this._myLenBuffer.Length, receiveData.Length);
 88                     receiveData = nData;
 89                     nData = null;
 90                     this._myLenBuffer = null;
 91                 }
 92                 else //全新包(包头完整的)
 93                 {
 94                     packageLength = TcpPackage.GetLength(receiveData);
 95                     if (packageLength == 0)
 96                         return;
 97                 }
 98                 if (packageLength < receiveData.Length)
 99                 {
100                     var package = TcpPackage.Parse(receiveData);
101                     if (action != null && package != null)
102                     {
103                         action(package);
104                     }
105 
106                     var slen = TcpPackage.GetLength(receiveData, package.Length);
107                     if (slen >= 9)
108                     {
109                         var next = new byte[receiveData.Length - package.Length];
110                         Buffer.BlockCopy(receiveData, package.Length, next, 0, next.Length);
111                         this.UnPackage(next, action);
112                     }
113                 }
114                 else if (packageLength == receiveData.Length)
115                 {
116                     var package = TcpPackage.Parse(receiveData);
117                     if (action != null && package != null)
118                     {
119                         action(package);
120                     }
121                 }
122                 else if (packageLength > receiveData.Length)
123                 {
124                     this.count = packageLength;
125                     this._myBuffer = new byte[packageLength];
126                     Buffer.BlockCopy(receiveData, 0, this._myBuffer, 0, receiveData.Length);
127                     this.offset = receiveData.Length;
128                 }
129                 receiveData = null;
130 
131             }
132             else //跨包取内容的
133             {
134                 if (receiveData.Length + offset < count) //包内容超出
135                 {
136                     Buffer.BlockCopy(receiveData, 0, this._myBuffer, offset, receiveData.Length);
137                     offset += receiveData.Length;
138                 }
139                 else if (receiveData.Length + offset >= count) //包内容短的
140                 {
141                     var packageLast = count - offset;
142                     Buffer.BlockCopy(receiveData, 0, this._myBuffer, offset, packageLast);
143                     var package = TcpPackage.Parse(this._myBuffer);
144                     if (action != null && package != null)
145                     {
146                         action(package);
147                     }
148                     this._myBuffer = null;
149                     count = offset = 0;
150                     var receiveLast = receiveData.Length - packageLast;
151                     if (receiveLast >= 4)//包含包头长度
152                     {
153                         var packageLength = TcpPackage.GetLength(receiveData, packageLast);
154                         if (packageLength > 0)
155                         {
156                             if (receiveLast > packageLength)
157                             {
158                                 var nextData = new byte[receiveLast];
159                                 Buffer.BlockCopy(receiveData, packageLast, nextData, 0, receiveLast);
160                                 this.UnPackage(nextData, action);
161                             }
162                             else
163                             {
164                                 this._myBuffer = new byte[packageLength];
165                                 Buffer.BlockCopy(receiveData, packageLast, this._myBuffer, 0, receiveLast);
166                                 offset = receiveLast;
167                                 count = packageLength;
168                             }
169                         }
170                         else
171                         {
172                             this._myBuffer = null;
173                             count = offset = 0;
174                             this._myLenBuffer = null;
175                         }
176                     }
177                     else if (receiveLast > 0)//不包含包头长度
178                     {
179                         this._myLenBuffer = new byte[receiveLast];
180                         Buffer.BlockCopy(receiveData, packageLast, this._myLenBuffer, 0, receiveLast);
181                         if (TcpPackage.GetLength(this._myLenBuffer) == 0)
182                         {
183                             this._myLenBuffer = null;
184                         }
185                         this._myBuffer = null;
186                         count = offset = 0;
187                     }
188                 }
189                 receiveData = null;
190             }
191         }
192 
193         public byte[] ReceiveBuffer
194         {
195             get; set;
196         }
197 
198         public void ClearReceiveBuffer()
199         {
200             for (int i = 0; i < this.ReceiveBuffer.Length; i++)
201             {
202                 this.ReceiveBuffer[i] = 0;
203             }
204         }
205     }
206 }
View Code

   有了解包就可以发超长消息、文件等

 

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

异步tcp通信——APM.Core 解包

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

异步tcp通信——APM.ConsoleDemo


转载请标明本文来源:http://www.cnblogs.com/yswenli/
更多内容欢迎star作者的github:https://github.com/yswenli/APM
如果发现本文有什么问题和任何建议,也随时欢迎交流~

 

posted @ 2017-01-09 17:58  yswenli  阅读(705)  评论(0编辑  收藏  举报