// 处理 Server 端可能发来的 Close // return value: // -1 error // 0 不是Close // 1 是Close,已经迫使ZChannel处于尚未初始化状态 // return InitialResult: // 在 InitialResult::ResultInfo 中返回诊断信息 async Task <InitialResult> CheckServerCloseRequest() { if (this._channel.Connected == false || this._channel.DataAvailable == false) { return(new InitialResult()); // 没有发现问题 } // 注意调用返回后如果发现出错,调主要主动 Close 和重新分配 TcpClient RecvResult result = await ZChannel.SimpleRecvTcpPackage(this._channel._client, -1).ConfigureAwait(false); if (result.Value == -1) { this.CloseConnection(); return(new InitialResult { Value = -1, ErrorInfo = result.ErrorInfo }); } BerTree tree1 = new BerTree(); // TODO: 这里需要捕获异常,然后把 Package Dump 到日志文件(base64 形态),便于事后分析调试 tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); if (tree1.GetAPDuRoot().m_uTag != BerTree.z3950_close) { // 不是Close return(new InitialResult { Value = 0 }); } CLOSE_REQUEST closeStruct = new CLOSE_REQUEST(); int nRet = BerTree.GetInfo_closeRequest( tree1.GetAPDuRoot(), ref closeStruct, out string strError); if (nRet == -1) { this.CloseConnection(); return(new InitialResult { Value = -1, ErrorInfo = strError }); } this.CloseConnection(); return(new InitialResult { Value = 1, ResultInfo = closeStruct.m_strDiagnosticInformation }); }
// 处理 Server 端可能发来的 Close // return value: // -1 error // 0 不是Close // 1 是Close,已经迫使ZChannel处于尚未初始化状态 // return InitialResult: // 在 InitialResult::ResultInfo 中返回诊断信息 async Task <InitialResult> CheckServerCloseRequest() { if (this._channel.Connected == false || this._channel.DataAvailable == false) { return(new InitialResult()); // 没有发现问题 } RecvResult result = await this._channel.SimpleRecvTcpPackage(); if (result.Value == -1) { return new InitialResult { Value = -1, ErrorInfo = result.ErrorInfo } } ; BerTree tree1 = new BerTree(); tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); if (tree1.GetAPDuRoot().m_uTag != BerTree.z3950_close) { // 不是Close return(new InitialResult { Value = 0 }); } CLOSE_REQUEST closeStruct = new CLOSE_REQUEST(); int nRet = BerTree.GetInfo_closeRequest( tree1.GetAPDuRoot(), ref closeStruct, out string strError); if (nRet == -1) { return new InitialResult { Value = -1, ErrorInfo = strError } } ; this.CloseConnection(); return(new InitialResult { Value = 1, ResultInfo = closeStruct.m_strDiagnosticInformation }); }
public async Task <RecvResult> SendAndRecv(byte[] baSend) { { Result result = await SimpleSendTcpPackage(this._client, baSend, baSend.Length).ConfigureAwait(false); if (result.Value == -1 || result.Value == 1) { this.CloseSocket(); return(new RecvResult(result) { Value = -1, //ErrorInfo = result.ErrorInfo, //ErrorCode = result.ErrorCode }); } } { //byte[] baPackage = null; //int nRecvLen = 0; // 注意调用返回后如果发现出错,调主要主动 Close 和重新分配 TcpClient RecvResult result = await SimpleRecvTcpPackage(this._client, -1).ConfigureAwait(false); if (result.Value == -1) { this.CloseSocket(); return(new RecvResult(result)); } #if DEBUG if (result.Package != null) { Debug.Assert(result.Package.Length == result.Length, ""); } else { Debug.Assert(result.Length == 0, ""); } #endif // this.baRecv = result.Package; // this.eventFinished.Set(); return(result); } }
public async Task <RecvResult> SendAndRecv(byte[] baSend) { { Result result = await this.SimpleSendTcpPackage( baSend, baSend.Length); if (result.Value == -1 || result.Value == 1) { return new RecvResult { Value = -1, ErrorInfo = result.ErrorInfo } } ; } { //byte[] baPackage = null; //int nRecvLen = 0; RecvResult result = await this.SimpleRecvTcpPackage(); if (result.Value == -1) { return new RecvResult { Value = -1, ErrorInfo = result.ErrorInfo } } ; #if DEBUG if (result.Package != null) { Debug.Assert(result.Package.Length == result.Length, ""); } else { Debug.Assert(result.Length == 0, ""); } #endif // this.baRecv = result.Package; // this.eventFinished.Set(); return(result); } }
// 获得记录 // 本函数每次调用前,最好调用一次 TryInitialize() // 不确保一定可以获得nCount个 // parameters: // nStart 获取记录的开始位置(从0开始计数) public async Task <PresentResult> OncePresent( string strResultSetName, int nStart, int nCount, string strElementSetName, string strPreferredRecordSyntax) { if (nCount == 0) { return new PresentResult { Value = 0, ErrorInfo = "nCount 参数为 0,本次没有真正请求服务器获取记录" } } ; BerTree tree = new BerTree(); PRESENT_REQUEST struPresent_request = new PRESENT_REQUEST(); //byte[] baPackage = null; //int nRet; struPresent_request.m_strReferenceId = this._currentRefID; struPresent_request.m_strResultSetName = strResultSetName; // "default"; struPresent_request.m_lResultSetStartPoint = nStart + 1; struPresent_request.m_lNumberOfRecordsRequested = nCount; struPresent_request.m_strElementSetNames = strElementSetName; struPresent_request.m_strPreferredRecordSyntax = strPreferredRecordSyntax; int nRet = tree.PresentRequest(struPresent_request, out byte[] baPackage); if (nRet == -1) { return new PresentResult { Value = -1, ErrorInfo = "CBERTree::PresentRequest() fail!" } } ; if (this._channel.Connected == false) { this.CloseConnection(); return(new PresentResult { Value = -1, ErrorInfo = "socket尚未连接或者已经被关闭" }); } #if DUMPTOFILE DeleteFile("presentrequest.bin"); DumpPackage("presentrequest.bin", (char *)baPackage.GetData(), baPackage.GetSize()); DeleteFile("presentrequest.txt"); tree.m_RootNode.DumpToFile("presentrequest.txt"); #endif BerTree tree1 = new BerTree(); { RecvResult result = await this._channel.SendAndRecv( baPackage); if (result.Value == -1) { return(new PresentResult(result)); } #if DUMPTOFILE DeleteFile("presendresponse.bin"); DumpPackage("presentresponse.bin", (char *)baPackage.GetData(), baPackage.GetSize()); #endif tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); } #if DUMPTOFILE DeleteFile("PresentResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("PresentResponse.txt"); #endif SEARCH_RESPONSE search_response = new SEARCH_RESPONSE(); nRet = BerTree.GetInfo_PresentResponse(tree1.GetAPDuRoot(), ref search_response, out RecordCollection records, true, out string strError); if (nRet == -1) { return new PresentResult { Value = -1, ErrorInfo = strError } } ; SetElementSetName(records, strElementSetName); if (search_response.m_diagRecords.Count != 0) { return new PresentResult { Value = -1, ErrorInfo = "error diagRecords:\r\n\r\n---\r\n" + search_response.m_diagRecords.GetMessage() } } ; return(new PresentResult { Records = records }); }
// 检索 // 本函数每次调用前,最好调用一次 TryInitialize() // parameters: // strQuery Search() 专用的检索式。注意,不是一个检索词那么简单 // dbnames 一般是从 targetInfo.DbNames 里面获得。或者从中选择一个数据库名用在这里 // strPreferredRecordSyntax 一般是从 targetInfo.PreferredRecordSyntax 获得即可 // result.Value: // -1 error // 0 fail // 1 succeed // result.ResultCount: // 命中结果集内记录条数 (当 result.Value 为 1 时) public async Task <SearchResult> Search( string strQuery, Encoding queryTermEncoding, string[] dbnames, string strPreferredRecordSyntax, string strResultSetName) { BerTree tree = new BerTree(); SEARCH_REQUEST struSearch_request = new SEARCH_REQUEST { m_dbnames = dbnames }; Debug.Assert(struSearch_request.m_dbnames.Length != 0, ""); struSearch_request.m_strReferenceId = this._currentRefID; struSearch_request.m_lSmallSetUpperBound = 0; struSearch_request.m_lLargeSetLowerBound = 1; struSearch_request.m_lMediumSetPresentNumber = 0; struSearch_request.m_nReplaceIndicator = 1; struSearch_request.m_strResultSetName = strResultSetName; // "default"; struSearch_request.m_strSmallSetElementSetNames = ""; struSearch_request.m_strMediumSetElementSetNames = ""; struSearch_request.m_strPreferredRecordSyntax = strPreferredRecordSyntax; // ZTargetControl.GetLeftValue(this.TargetInfo.PreferredRecordSyntax); // BerTree.MARC_SYNTAX; struSearch_request.m_strQuery = strQuery; struSearch_request.m_nQuery_type = 1; struSearch_request.m_queryTermEncoding = queryTermEncoding; // m_search_response.m_lErrorCode = 0; byte[] baPackage = null; try { // 这里可能抛出异常 tree.SearchRequest(struSearch_request, out baPackage); } catch (Exception ex) { return(new SearchResult { Value = -1, ErrorInfo = "CBERTree::SearchRequest() Exception: " + ex.Message }); } if (this._channel.Connected == false) { this.CloseConnection(); return(new SearchResult { Value = -1, ErrorInfo = "socket尚未连接或者已经被关闭" }); } #if DUMPTOFILE string strBinFile = this.MainForm.DataDir + "\\searchrequest.bin"; File.Delete(strBinFile); DumpPackage(strBinFile, baPackage); string strLogFile = this.MainForm.DataDir + "\\searchrequest.txt"; File.Delete(strLogFile); tree.m_RootNode.DumpToFile(strLogFile); #endif #if NO nRet = CheckConnect( out strError); if (nRet == -1) { return(-1); } #endif BerTree tree1 = new BerTree(); { RecvResult result = await this._channel.SendAndRecv( baPackage); if (result.Value == -1) { return(new SearchResult(result)); } #if NO #if DEBUG if (nRet == 0) { Debug.Assert(strError == "", ""); } #endif #endif #if DUPMTOFILE DeleteFile("searchresponse.bin"); DumpPackage("searchresponse.bin", (char *)baOutPackage.GetData(), baOutPackage.GetSize()); #endif tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); } SEARCH_RESPONSE search_response = new SEARCH_RESPONSE(); int nRet = BerTree.GetInfo_SearchResponse(tree1.GetAPDuRoot(), ref search_response, true, out string strError); if (nRet == -1) { return new SearchResult { Value = -1, ErrorInfo = strError } } ; #if DUMPTOFILE DeleteFile("SearchResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("SearchResponse.txt"); #endif { SearchResult result = new SearchResult(); result.ResultCount = (int)search_response.m_lResultCount; if (search_response.m_nSearchStatus != 0) // 不一定是1 { result.Value = 1; return(result); } result.ErrorInfo = "Search Fail: diagRecords:\r\n" + search_response.m_diagRecords.GetMessage(); result.Value = 0; // search fail return(result); } }
// 执行初始化 // 同步模式 // parameters: // strResultInfo [out]返回说明初始化结果的文字 // return Value: // -1 出错 // 0 成功 async Task <InitialResult> Initial( TargetInfo targetinfo, bool bIgnoreReferenceID, string reference_id) { string strResultInfo = ""; BerTree tree = new BerTree(); INIT_REQUEST struInit_request = new INIT_REQUEST(); // TargetInfo targetinfo = connection.TargetInfo; if (this._channel.Initialized == true) { return new InitialResult { Value = -1, ErrorInfo = "先前已经初始化过了,不应重复初始化" } } ; // 不能重复调用 struInit_request.m_strReferenceId = reference_id; struInit_request.m_strOptions = "yynnnnnnnnnnnnnnnn"; // "yyynynnyynynnnyn"; struInit_request.m_lPreferredMessageSize = 0x100000; ////16384; struInit_request.m_lExceptionalRecordSize = 0x100000; if (String.IsNullOrEmpty(targetinfo.UserName) == false) { struInit_request.m_strID = targetinfo.UserName; struInit_request.m_strPassword = targetinfo.Password; struInit_request.m_strGroupID = targetinfo.GroupID; struInit_request.m_nAuthenticationMethod = targetinfo.AuthenticationMethod; } else { struInit_request.m_strID = ""; struInit_request.m_strPassword = ""; struInit_request.m_strGroupID = ""; struInit_request.m_nAuthenticationMethod = -1; } struInit_request.m_strImplementationId = "DigitalPlatform"; struInit_request.m_strImplementationVersion = "1.2.0"; struInit_request.m_strImplementationName = "Z3950_library"; if (targetinfo.CharNegoUTF8 == true) { struInit_request.m_charNego = new CharsetNeogatiation(); struInit_request.m_charNego.EncodingLevelOID = CharsetNeogatiation.Utf8OID; // "1.0.10646.1.0.8"; // utf-8 struInit_request.m_charNego.RecordsInSelectedCharsets = (targetinfo.CharNegoRecordsUTF8 == true ? 1 : 0); } int nRet = tree.InitRequest(struInit_request, targetinfo.DefaultQueryTermEncoding, out byte[] baPackage); if (nRet == -1) { return new InitialResult { Value = -1, ErrorInfo = "CBERTree::InitRequest() fail!" } } ; if (this._channel.Connected == false) { this.CloseConnection(); return(new InitialResult { Value = -1, ErrorInfo = "socket尚未连接或者已经被关闭" }); } #if DUMPTOFILE DeleteFile("initrequest.bin"); DumpPackage("initrequest.bin", (char *)baPackage.GetData(), baPackage.GetSize()); DeleteFile("initrequest.txt"); tree.m_RootNode.DumpToFile("initrequest.txt"); #endif RecvResult result = await this._channel.SendAndRecv( baPackage); if (result.Value == -1) { return(new InitialResult(result)); } #if DUMPTOFILE DeleteFile("initresponse.bin"); DumpPackage("initresponse.bin", (char *)baOutPackage.GetData(), baOutPackage.GetSize()); #endif //////////////////////////////////////////////////////////////// BerTree tree1 = new BerTree(); tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); #if DUMPTOFILE DeleteFile("InitResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("InitResponse.txt"); #endif INIT_RESPONSE init_response = new INIT_RESPONSE(); nRet = BerTree.GetInfo_InitResponse(tree1.GetAPDuRoot(), ref init_response, out string strError); if (nRet == -1) { return new InitialResult { Value = -1, ErrorInfo = strError } } ; if (bIgnoreReferenceID == false) { // 可以帮助发现旧版本dp2zserver的错误 if (struInit_request.m_strReferenceId != init_response.m_strReferenceId) { strError = "请求的 reference id [" + struInit_request.m_strReferenceId + "] 和 响应的 reference id [" + init_response.m_strReferenceId + "] 不一致!"; return(new InitialResult { Value = -1, ErrorInfo = strError }); } } // 2007/11/5检查version和options bool bOption_0 = BerTree.GetBit(init_response.m_strOptions, 0); if (bOption_0 == false) { strError = "服务器响应的 option bit 0 表示不支持 search"; return(new InitialResult { Value = -1, ErrorInfo = strError }); } bool bOption_1 = BerTree.GetBit(init_response.m_strOptions, 1); if (bOption_1 == false) { strError = "服务器响应的 option bit 1 表示不支持 present"; return(new InitialResult { Value = -1, ErrorInfo = strError }); } if (init_response.m_nResult != 0) { strError = "Initial OK"; } else { strError = "Initial被拒绝。\r\n\r\n错误码 [" + init_response.m_lErrorCode.ToString() + "]\r\n错误消息[" + init_response.m_strErrorMessage + "]"; strResultInfo = BuildInitialResultInfo(init_response); return(new InitialResult { Value = -1, ErrorInfo = strError, ResultInfo = strResultInfo }); } /* * this->m_init_strOption = init_response.m_strOptions; * this->m_init_lPreferredMessageSize = init_response.m_lPreferredMessageSize; * this->m_init_lExceptionalRecordSize = init_response.m_lExceptionalRecordSize; * this->m_init_nResult = init_response.m_nResult; * */ this._channel.Initialized = true; // 字符集协商 if (init_response.m_charNego != null && BerTree.GetBit(init_response.m_strOptions, 17) == true) { if (init_response.m_charNego.EncodingLevelOID == CharsetNeogatiation.Utf8OID) { // 临时修改检索词的编码方式。 // 但是还无法反映到PropertyDialog上。最好能反馈。 targetinfo.DefaultQueryTermEncoding = Encoding.UTF8; targetinfo.Changed = true; if (init_response.m_charNego.RecordsInSelectedCharsets == 1) { this.ForcedRecordsEncoding = Encoding.UTF8; } } } strResultInfo = BuildInitialResultInfo(init_response); return(new InitialResult { Value = 0, ErrorInfo = strError, ResultInfo = strResultInfo }); }
static int DEFAULT_CLEAR_SECONDS = 10; // TCP 连接后,登录以前,能存活的秒数。超过这个秒数就可能被管理线程 Close 和清除 // 处理一个通道的通讯活动 public async override void HandleClient(TcpClient tcpClient, Action close_action, CancellationToken token) { SipChannel channel = _tcpChannels.Add(tcpClient, () => { return(new SipChannel()); }) as SipChannel; channel.Timeout = TimeSpan.FromSeconds(DEFAULT_CLEAR_SECONDS); // 在登录以前,TCP 连接可以存活 DEFAULT_CLEAR_SECONDS 秒。DEFAULT_CLEAR_SECONDS 秒以后还不接到登录请求,TCP 连接会被自动清除。登录后,Timeout 则会被设置为实例参数 AutoClearSeconds 值 List <byte> cache = new List <byte>(); try { string ip = ""; try { ip = GetClientIP(tcpClient); channel.Touch(); int i = 0; bool running = true; while (running) { if (token != null && token.IsCancellationRequested) { return; } byte[] response = null; { // TODO: 也可以在这里等待多少秒,然后超时以后,条件符合时,自动清除 TCP 通道。可以弥补管理线程轮次不及时的缺点 // 注意调用返回后如果发现返回 null 或者抛出了异常,调主要主动 Close 和重新分配 TcpClient RecvResult result = await TcpChannel.SimpleRecvTcpPackage(tcpClient, cache, (package, start, length) => { return(FindTerminator(package, start, length)); }, this.MaxPackageLength).ConfigureAwait(false); // 2018/10/10 add configure if (result.Value == -1) { if (result.ErrorCode == "ConnectionAborted") { Console.WriteLine("client close on request " + i); } else { Console.WriteLine("recv error on request " + i + ": " + result.ErrorInfo); } break; } channel.Terminator = (byte)result.Terminator; Console.WriteLine("request " + i); // byte [] 转换为 string channel.Touch(); if (token != null && token.IsCancellationRequested) { return; } ProcessSipRequestEventArgs e = new ProcessSipRequestEventArgs(); e.Request = result.Package; this.ProcessRequest(channel, e); response = e.Response; } channel.Touch(); if (token != null && token.IsCancellationRequested) { return; } { // 注意调用返回 result.Value == -1 情况下,要及时 Close TcpClient Result result = await TcpChannel.SimpleSendTcpPackage(tcpClient, response, response.Length).ConfigureAwait(false); // 2018/10/10 add configure channel.Touch(); if (result.Value == -1 || result.Value == 1) { Console.WriteLine("error on response " + i + ": " + result.ErrorInfo); break; } } i++; } } catch (Exception ex) { string strError = "ip:" + ip + " HandleClient() 异常: " + ExceptionUtil.GetExceptionText(ex); LibraryManager.Log?.Error(strError); // Console.WriteLine(strError); } finally { // tcpClient.Close(); // 清除全局结果集 } } finally { _tcpChannels.Remove(channel); channel.Close(); if (close_action != null) { close_action.Invoke(); } } }
// 接收响应包 // 注意调用返回后如果发现出错,调主要主动 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); }
// 接收响应包 internal async Task <RecvResult> SimpleRecvTcpPackage() { 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) { strError = "通讯中断"; goto ERROR1; } try { wRet = await _client.GetStream().ReadAsync(result.Package, nInLen, result.Package.Length - nInLen); } catch (SocketException ex) { if (ex.ErrorCode == 10035) { System.Threading.Thread.Sleep(100); continue; } strError = "recv出错: " + ex.Message; goto ERROR1; } catch (Exception ex) { strError = "recv出错: " + ex.Message; goto ERROR1; } if (wRet == 0) { strError = "Closed by remote peer"; goto ERROR1; } // 得到包的长度 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) { // 扩大缓冲区 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); ERROR1: // this.CloseSocket(); // baPackage = null; return(new RecvResult { Value = -1, ErrorInfo = strError }); }