// 接收响应包 // 注意调用返回后如果发现出错,调主要主动 Close 和重新分配 TcpClient // parameters: // nMaxLength 读入等待处理的 bytes 极限数字。超过了这个,还没有找到结束符,就会抛出异常。意在防范攻击。-1 表示不限制 // touch_func 回调函数,用于保持通道活跃 public static async Task <RecvResult> SimpleRecvTcpPackage(TcpClient _client, int nMaxLength, delegate_touch touch_func = null) { // string strError = ""; RecvResult result = new RecvResult(); int nInLen; int wRet = 0; bool bInitialLen = false; Debug.Assert(_client != null, "client为空"); result.Package = new byte[4096]; nInLen = 0; result.Length = 4096; //COMM_BUFF_LEN; while (nInLen < result.Length) { if (_client == null) { return(new RecvResult { Value = -1, ErrorInfo = "通讯中断" }); } try { wRet = await _client.GetStream().ReadAsync(result.Package, nInLen, result.Package.Length - nInLen).ConfigureAwait(false); touch_func?.Invoke(); } catch (SocketException ex) { if (ex.ErrorCode == 10035) { System.Threading.Thread.Sleep(100); continue; } return(new RecvResult { Value = -1, ErrorInfo = "recv出错1: " + ex.Message, // "ConnectionAborted" ErrorCode = ((SocketException)ex).SocketErrorCode.ToString() }); } catch (Exception ex) { result.Exception = ex; if (ex is IOException && ex.InnerException is SocketException) { // "ConnectionAborted" result.ErrorCode = ((SocketException)ex.InnerException).SocketErrorCode.ToString(); } result.ErrorInfo = "recv出错2: " + ex.Message; result.Value = -1; return(result); } if (wRet == 0) { return(new RecvResult { Value = -1, ErrorCode = "Closed", ErrorInfo = "Closed by remote peer" }); } // 得到包的长度 if ((wRet >= 1 || nInLen >= 1) && bInitialLen == false) { bool bRet = BerNode.IsCompleteBER(result.Package, 0, nInLen + wRet, out long remainder); if (bRet == true) { result.Length = nInLen + wRet; break; } } nInLen += wRet; if (nInLen >= result.Package.Length && bInitialLen == false) { // 扩大缓冲区 if (nMaxLength != -1 && result.Package.Length >= nMaxLength) { throw new Exception("接收超过 " + nMaxLength + " bytes 也没有找到通讯包结束符"); } byte[] temp = new byte[result.Package.Length + 4096]; Array.Copy(result.Package, 0, temp, 0, nInLen); result.Package = temp; result.Length = result.Package.Length; } } // 最后规整缓冲区尺寸,如果必要的话 if (result.Package.Length > result.Length) { byte[] temp = new byte[result.Length]; Array.Copy(result.Package, 0, temp, 0, result.Length); result.Package = temp; } return(result); #if NO ERROR1: // this.CloseSocket(); // baPackage = null; return(new RecvResult { Value = -1, ErrorInfo = strError, ErrorCode = result.ErrorCode }); #endif }
// (支持 Pipeline 的版本) // 接收通讯包 // 本函数支持 Pipeline 方式。 // parameters: // cache 用来支持 Pipeline 方式,把多于一个通讯包的 bytes 部分,存储起来,下次先处理这部分内容 // 如果为 null,表示不支持 Pipeline 方式 // nMaxLength 读入等待处理的 bytes 极限数字。超过了这个,还没有找到结束符,就会抛出异常。意在防范攻击。-1 表示不限制 public static async Task <RecvResult> SimpleRecvTcpPackage(TcpClient client, List <byte> cache, Delegate_isComplete procIsComplete, delegate_touch touch_func = null, int nMaxLength = 4096) { RecvResult result = new RecvResult(); Debug.Assert(client != null, "client为空"); List <byte> package = new List <byte>(); int CHUNK_SIZE = 4096; // 优先从 cache 中复制数据过来进行处理 if (cache != null && cache.Count > 0) { package = cache; cache.Clear(); } while (true) { if (client == null) { return(new RecvResult { Value = -1, ErrorInfo = "通讯中断", ErrorCode = "abort" }); } // byte[] temp = new byte[CHUNK_SIZE]; byte[] temp = ArrayPool <byte> .Shared.Rent(CHUNK_SIZE); int current = 0; try { current = await client.GetStream().ReadAsync(temp, 0, CHUNK_SIZE).ConfigureAwait(false); touch_func?.Invoke(); if (current > 0) { if (current == temp.Length) { package.AddRange(temp); } else { int i = 0; foreach (byte b in temp) { if (i >= current) { break; } package.Add(b); i++; } } // package.AddRange(GetValues<byte>(temp, current)); } } catch (SocketException ex) { if (ex.ErrorCode == 10035) { System.Threading.Thread.Sleep(100); continue; } return(new RecvResult { Value = -1, ErrorInfo = "recv出错1: " + ex.Message, // "ConnectionAborted" ErrorCode = ((SocketException)ex).SocketErrorCode.ToString() }); } catch (Exception ex) { result.Exception = ex; if (ex is IOException && ex.InnerException is SocketException) { // "ConnectionAborted" result.ErrorCode = ((SocketException)ex.InnerException).SocketErrorCode.ToString(); } result.ErrorInfo = "recv出错2: " + ex.Message; result.Value = -1; return(result); } finally { ArrayPool <byte> .Shared.Return(temp); } // 得到包的长度 if (package.Count >= 1) { var ret = procIsComplete(package.ToArray(), 0, package.Count); if (ret.Item1 > 0) { result.Length = ret.Item1; result.Terminator = ret.Item2; // 将结束符后面多出来的部分复制到 cache 中,以便下一次调用处理 if (result.Length < package.Count) { if (cache == null) { throw new Exception("当前不支持 Pipeline 方式的请求。发现前端一次性发送了多于一个通讯包"); } for (int i = result.Length; i < package.Count; i++) { cache.Add(package[i]); } } break; } } if (current == 0) { return(new RecvResult { Value = -1, ErrorCode = "Closed", ErrorInfo = "Closed by remote peer" }); } if (nMaxLength != -1 && package.Count >= nMaxLength) { throw new Exception("接收超过 " + nMaxLength + " bytes 也没有找到通讯包结束符"); } } // 最后规整缓冲区尺寸,如果必要的话 if (package.Count > result.Length) { package.RemoveRange(result.Length, package.Count - result.Length); } result.Package = package.ToArray(); return(result); }