异步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 }
有了解包就可以发超长消息、文件等
异步tcp通信——APM.Core 服务端概述
异步tcp通信——APM.Core 解包
异步tcp通信——APM.Server 消息推送服务的实现
异步tcp通信——APM.ConsoleDemo
转载请标明本文来源:http://www.cnblogs.com/yswenli/
更多内容欢迎star作者的github:https://github.com/yswenli/APM
如果发现本文有什么问题和任何建议,也随时欢迎交流~