Beispiel #1
0
        // 接收通讯包
        // 本函数支持 Pipeline 方式。
        // parameters:
        //      cache   用来支持 Pipeline 方式,把多于一个通讯包的 bytes 部分,存储起来,下次先处理这部分内容
        //              如果为 null,表示不支持 Pipeline 方式
        //      nMaxLength  读入等待处理的 bytes 极限数字。超过了这个,还没有找到结束符,就会抛出异常。意在防范攻击。-1 表示不限制
        public static async Task <RecvResult> SimpleRecvTcpPackage(TcpClient client,
                                                                   List <byte> cache,
                                                                   Delegate_isComplete procIsComplete,
                                                                   int nMaxLength = 4096)
        {
            // string strError = "";
            RecvResult result = new RecvResult();

            int recieved = 0;   // 累计读取的 byte 数
            int current  = 0;   // 本次读取的 byte 数

            // bool bInitialLen = false;

            Debug.Assert(client != null, "client为空");

            int CHUNK_SIZE = 4096;

            result.Package = new byte[CHUNK_SIZE];
            recieved       = 0;
            result.Length  = CHUNK_SIZE;

            // 优先从 cache 中复制数据过来进行处理
            if (cache != null && cache.Count > 0)
            {
                result.Package = EnlargeBuffer(cache.ToArray(), CHUNK_SIZE);
                result.Length  = result.Package.Length;
                recieved       = result.Length;
                cache.Clear();
            }

            while (recieved < result.Length)
            {
                if (client == null)
                {
                    return(new RecvResult
                    {
                        Value = -1,
                        ErrorInfo = "通讯中断",
                        ErrorCode = "abort"
                    });
                }

                try
                {
                    current = await client.GetStream().ReadAsync(result.Package,
                                                                 recieved,
                                                                 result.Package.Length - recieved).ConfigureAwait(false);
                }
                catch (SocketException ex)
                {
                    if (ex.ErrorCode == 10035)
                    {
                        System.Threading.Thread.Sleep(100);
                        continue;
                    }
                    return(new RecvResult
                    {
                        Exception = ex,
                        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 (current == 0)
                {
                    return(new RecvResult
                    {
                        Value = -1,
                        ErrorCode = "Closed",
                        ErrorInfo = "Closed by remote peer"
                    });
                }

                // 得到包的长度

                if (current >= 1 || recieved >= 1)
                {
                    var ret = procIsComplete(result.Package,
                                             0,
                                             recieved + current);
                    if (ret.Item1 > 0)
                    {
                        result.Length     = ret.Item1;
                        result.Terminator = ret.Item2;
                        // 将结束符后面多出来的部分复制到 cache 中,以便下一次调用处理
                        if (result.Length > recieved + current) // ?? bug
                        {
                            if (cache == null)
                            {
                                throw new Exception("当前不支持 Pipeline 方式的请求。发现前端一次性发送了多于一个通讯包");
                            }
                            for (int i = result.Length; i < recieved + current; i++)
                            {
                                cache.Add(result.Package[i]);
                            }
                        }
                        break;
                    }
                }

                recieved += current;
                if (recieved >= result.Package.Length)
                {
#if NO
                    // 扩大缓冲区
                    byte[] temp = new byte[result.Package.Length + 4096];
                    Array.Copy(result.Package, 0, temp, 0, nInLen);
                    result.Package = temp;
                    result.Length  = result.Package.Length;
#endif
                    if (nMaxLength != -1 && result.Package.Length >= nMaxLength)
                    {
                        throw new Exception("接收超过 " + nMaxLength + " bytes 也没有找到通讯包结束符");
                    }
                    // 扩大缓冲区
                    result.Package = EnlargeBuffer(result.Package, CHUNK_SIZE);
                    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);
        }
Beispiel #2
0
        // (支持 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);
        }