zoukankan      html  css  js  c++  java
  • 异步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
    如果发现本文有什么问题和任何建议,也随时欢迎交流~

  • 相关阅读:
    MySQL关于check约束无效的解决办法
    关于constraint的用法
    MySQL关于Duplicate entry '1' for key 'PRIMARY'错误
    iOS实现高斯模糊效果(Swift版本)
    iOS获取视频中的指定帧的两种方法
    Java关于e.printStackTrace()介绍
    iOS关于JSONKit解析Unicode字符内容出错,问题出在u0000
    Java转型(向上转型和向下转型)
    添加删除Windows组件里没有IIS(Internet信息服务)项的解决方法
    Windows2003:“无法加载安装程序库wbemupgd.dll
  • 原文地址:https://www.cnblogs.com/yswenli/p/6266017.html
Copyright © 2011-2022 走看看