Example #1
0
        private async Task DoSendAsync()
        {
            Exception error = null;

            DebugLog("starting send loop");
            try
            {
                while (true)
                {
                    DebugLog("awaiting data from pipe...");
                    if (_sendToSocket.Reader.TryRead(out var result))
                    {
                        CounterHelper.Incr(Counter.SocketPipeReadReadSync);
                    }
                    else
                    {
                        CounterHelper.Incr(Counter.OpenSendReadAsync);
                        var read = _sendToSocket.Reader.ReadAsync();
                        CounterHelper.Incr(read.IsCompleted ? Counter.SocketPipeReadReadSync : Counter.SocketPipeReadReadAsync);
                        result = await read;
                        CounterHelper.Decr(Counter.OpenSendReadAsync);
                    }

                    var buffer = result.Buffer;
                    if (result.IsCanceled || (result.IsCompleted && buffer.IsEmpty))
                    {
                        DebugLog(result.IsCanceled ? "cancelled" : "complete");
                        break;
                    }

                    try
                    {
                        if (!buffer.IsEmpty)
                        {
                            // 说明:send方向上是read from pipe and send to socket,所以这里回调应该是
                            // 执行在ReaderScheduler上
                            if (_writerArgs == null)
                            {
                                _writerArgs = new SocketAwaitableEventArgs(InlineWrites ? null : _sendOptions.ReaderScheduler);
                            }

                            DebugLog($"sending {buffer.Length} bytes over socket...");
                            CounterHelper.Incr(Counter.OpenSendWriteAsync);

                            DoSend(Socket, _writerArgs, buffer, Name);
                            CounterHelper.Incr(_writerArgs.IsCompleted ? Counter.SocketSendAsyncSync : Counter.SocketSendAsyncAsync);
                            DebugLog(_writerArgs.IsCompleted ? "send is sync" : "send is async");
                            var bytesSend = await _writerArgs;
                            Interlocked.Add(ref _totalBytesSent, bytesSend);
                            CounterHelper.Decr(Counter.OpenSendWriteAsync);
                        }
                        else if (result.IsCompleted)
                        {
                            DebugLog("completed");
                            break;
                        }
                    }
                    finally
                    {
                        DebugLog("advancing");
                        _sendToSocket.Reader.AdvanceTo(buffer.End);
                    }
                }
                TrySetShutdown(PipeShutdownKind.WriteEndOfStream);
            }
            catch (SocketException ex) when(IsConnectionResetError(ex.SocketErrorCode))
            {
                TrySetShutdown(PipeShutdownKind.WriteSocketError, ex.SocketErrorCode);
                DebugLog($"fail: {ex.SocketErrorCode}");
                error = new ConnectionResetException(ex.Message, ex);
            }
            catch (SocketException ex) when(IsConnectionAbortError(ex.SocketErrorCode))
            {
                TrySetShutdown(PipeShutdownKind.WriteSocketError, ex.SocketErrorCode);
                DebugLog($"fail: {ex.SocketErrorCode}");
                // This should always be ignored since Shutdown() must have already been called by Abort().
                error = ex;
            }
            catch (ObjectDisposedException ex)
            {
                TrySetShutdown(PipeShutdownKind.WriteDisposed);
                DebugLog("fail: disposed");
                error = ex;
            }
            catch (IOException ex)
            {
                TrySetShutdown(PipeShutdownKind.WriteIOException);
                DebugLog($"fail - io: {ex.Message}");
                error = ex;
            }
            catch (Exception ex)
            {
                TrySetShutdown(PipeShutdownKind.WriteException);
                DebugLog($"fail: {ex.Message}");
                error = ex;
            }
            finally
            {
                Shutdown(error);
                error = error ?? _shutdownReason;

                // close *both halves* of the send pipe; we're not
                // listening *and* we don't want anyone trying to write
                DebugLog($"marking {nameof(Output)} as complete");
                try { _sendToSocket.Writer.Complete(error); } catch { }
                try { _sendToSocket.Reader.Complete(error); } catch { }
                TrySetShutdown(error, PipeShutdownKind.OutputReaderCompleted);

                var args = _writerArgs;
                _writerArgs = null;
                if (args != null)
                {
                    try { args.Dispose(); } catch { }
                }
            }

            DebugLog(error == null ? "exiting with success" : $"exiting with failure: {error.Message}");
        }