예제 #1
0
        private void ProcessSend(SocketAsyncEventArgs e)
        {
            SendingContext sctx = null;

            try {
                sctx = (SendingContext)e.UserToken;
                if (e.SocketError != SocketError.Success)
                {
                    var err = e.SocketError;
                    ProcessSendFailed(sctx.SendingBatch, RpcErrorCode.SendFailed, new Exception("Send Body Failed: " + err));
                    Disconnect(e.SocketError);
                    RpcTcpBufferManager.Release(e);
                    e = null;
                }
                else
                {
                    _tracing.InfoFmt("Socket Send {0} Bytes", e.Count);
                    RpcTcpBufferManager.Release(e);
                    e = null;
                    SendPackets(sctx.NextPacket);
                }
            } catch (Exception ex) {
                _tracing.ErrorFmt(ex, "ProcessSend Failed {0}:{1}", e, e.Buffer.Length);
                Disconnect(ex, "ProcessSend");
            } finally {
                //
                // 保护,如果出现了异常,则在此处释放
                if (e != null)
                {
                    RpcTcpBufferManager.Release(e);
                }
            }
        }
예제 #2
0
        /// <summary>
        ///		发送报文
        ///		如果sendFirst == null, 则优先从queue中dequeue
        ///		否则, 先取出sendFirst, 然后再从queue中取
        ///		这是一个回调链,完全靠回调组织起来的,当_sending = 1时,存在一个回调链
        /// </summary>
        /// <param name="sendFirst"></param>
        private void SendPackets(IRpcTcpSendingPacket sendFirst)
        {
            int size;
            SocketAsyncEventArgs        eSend = null;
            List <IRpcTcpSendingPacket> batch = new List <IRpcTcpSendingPacket>();

            //
            // 阶段1. 获得第一个能够发送的报文
            try {
                //
                // 先至少放置一个报文进去
                if (sendFirst != null)
                {
                    batch.Add(sendFirst);
                }
                else
                {
                    if (_pendingPackets.Count == 0)
                    {
                        //
                        // 回调链的最终返回,只有当Queue完全清空以后,置空标记位
                        _sending = 0;
                        return;
                    }
                    else
                    {
                        lock (_syncSend) {
                            batch.Add(_pendingPackets.Dequeue());
                        }
                        _counter.SendPending.Decrement();
                    }
                }

                //
                // 获取第一个包的大小, 并估算对缓冲区的大小的需求
                size = GetExpectSize(batch[0]);
            } catch (Exception ex) {
                //
                // 在上面的代码块中如果出现异常,则本次发送失败
                _tracing.ErrorFmt(ex, "SendPackets 1 failed");
                ProcessSendFailed(batch, RpcErrorCode.SendFailed, ex);

                //
                // 扔出异常会导致连接断开,所以直接引发下一个调用链
                SendPackets(null);
                return;
            }


            //
            // 阶段2. 获取缓冲区,并写入数据
            try {
                //
                // 创建缓冲区, 如果过大会建立新缓冲区
                eSend = RpcTcpBufferManager.FetchSendArgs(size, _pendingPackets.Count);

                MemoryStream stream       = new MemoryStream(eSend.Buffer, 0, eSend.Buffer.Length, true, true);
                int          bufferRemain = eSend.Buffer.Length;

                //
                // 写入第一个报文
                TryWriteBuffer(batch[0], stream, bufferRemain);
                bufferRemain = bufferRemain - (int)stream.Position;

                //
                // 尝试向缓冲区内放置能够发送出去的最多的报文
                IRpcTcpSendingPacket packet = null;
                while (true)
                {
                    if (_pendingPackets.Count > 0)
                    {
                        lock (_syncSend) {
                            if (_pendingPackets.Count > 0)
                            {
                                packet = _pendingPackets.Dequeue();
                            }
                        }
                        _counter.SendPending.Decrement();
                    }
                    else
                    {
                        break;
                    }
                    int offsetBefore = (int)stream.Position;
                    if (TryWriteBuffer(packet, stream, bufferRemain))
                    {
                        batch.Add(packet);
                        packet = null;
                    }
                    else
                    {
                        break;
                    }
                    int offsetAfter = (int)stream.Position;
                    bufferRemain = bufferRemain - (offsetAfter - offsetBefore);
                }

                int bufferSize = (int)stream.Position;
                _counter.SendPerSec.Increment();
                _counter.SendTotal.Increment();

                _counter.SendMessageTotal.IncrementBy(batch.Count);
                _counter.SendMessagePerSec.IncrementBy(batch.Count);

                _counter.SendBytesPerSec.IncrementBy(bufferSize);
                _counter.SendBytesTotal.IncrementBy(bufferSize);

                eSend.UserToken = new SendingContext()
                {
                    NextPacket   = packet,
                    SendingBatch = batch,
                };

                if (eSend is RpcTcpAsyncArgs)
                {
                    ((RpcTcpAsyncArgs)eSend).Callback = delegate(SocketAsyncEventArgs e) {
                        ProcessSend(e);
                    };
                }
                else
                {
                    eSend.Completed += new EventHandler <SocketAsyncEventArgs>(
                        (sender, e) => ProcessSend(e)
                        );
                }

                eSend.SetBuffer(0, bufferSize);
            } catch (Exception ex) {
                //
                // 无论如何,先交回缓冲区
                RpcTcpBufferManager.Release(eSend);

                //
                // 在组织缓冲区的代码块中如果出现异常,则本次发送失败,整批失败
                _tracing.ErrorFmt(ex, "SendPackets 2 failed");
                ProcessSendFailed(batch, RpcErrorCode.SendFailed, ex);

                //
                // 扔出异常会导致连接断开,所以直接引发下一个调用链
                SendPackets(null);
                return;
            }

            if (!_socket.SendAsync(eSend))
            {
                ProcessSend(eSend);
            }
        }
예제 #3
0
        /// <summary>
        ///		断开连接,这个方法不会抛出异常
        /// </summary>
        /// <param name="err"></param>
        public void Close(Exception err)
        {
            if (_closed)
            {
                return;
            }
            else
            {
                lock (_syncClose) {
                    if (_closed)
                    {
                        return;
                    }
                    else
                    {
                        _closed    = true;
                        _connected = false;
                    }
                }
            }

            _counter.Connections.Decrement();
            if (_socket.Connected)
            {
                _socket.Shutdown(SocketShutdown.Both);
            }
            _socket.Close();
            _releasing = true;

            var l = new List <IRpcTcpSendingPacket>();

            lock (_syncSend) {
                while (_pendingPackets.Count > 0)
                {
                    l.Add(_pendingPackets.Dequeue());
                }
                _pendingPackets.Clear();
            }

            if (l.Count > 0)
            {
                _counter.SendPending.IncrementBy(-l.Count);
                ProcessSendFailed(l, RpcErrorCode.SendFailed, err);
            }

            if (_eRecv != null)
            {
                //
                // TODO: 应该有更优雅的实现方式
                // 最好 _eRecv有一个opertion的标志位, 如果正在recieve中,就在receive返回后Release(_eRecv),否则在此处release
                Thread.Sleep(500);
                RpcTcpBufferManager.Release(_eRecv);
            }

            if (err != null)
            {
                _counter.CorruptedTransmissions.Increment();
            }

            if (Disconnected != null)
            {
                Disconnected(this);
            }
        }