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                             else163                             {164                                 this._myBuffer = new byte[packageLength];165                                 Buffer.BlockCopy(receiveData, packageLast, this._myBuffer, 0, receiveLast);166                                 offset = receiveLast;167                                 count = packageLength;168                             }169                         }170                         else171                         {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[] ReceiveBuffer194         {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
如果发现本文有什么问题和任何建议,也随时欢迎交流~

 

收藏 打印