private static void DoSend(Socket socket, SocketAwaitableEventArgs args, ReadOnlyMemory <byte> memory, string name) { // The BufferList getter is much less expensive then the setter. if (args.BufferList != null) { args.BufferList = null; } #if SOCKET_STREAM_BUFFERS args.SetBuffer(MemoryMarshal.AsMemory(memory)); #else var segment = memory.GetArray(); args.SetBuffer(segment.Array, segment.Offset, segment.Count); #endif Helpers.DebugLog(name, $"## {nameof(socket.SendAsync)} {memory.Length}"); if (socket.SendAsync(args)) { Helpers.Incr(Counter.SocketSendAsyncSingleAsync); } else { Helpers.Incr(Counter.SocketSendAsyncSingleSync); args.Complete(); } }
private static void DoSend(Socket socket, SocketAwaitableEventArgs args, ReadOnlySequence <byte> buffer, string name) { if (buffer.IsSingleSegment) { DoSend(socket, args, buffer.First, name); return; } #if SOCKET_STREAM_BUFFERS if (!args.MemoryBuffer.IsEmpty) #else if (args.Buffer != null) #endif { args.SetBuffer(null, 0, 0); } args.BufferList = GetBufferList(args, buffer); Helpers.DebugLog(name, $"## {nameof(socket.SendAsync)} {buffer.Length}"); if (socket.SendAsync(args)) { Helpers.Incr(Counter.SocketSendAsyncMultiAsync); } else { Helpers.Incr(Counter.SocketSendAsyncMultiSync); args.Complete(); } }
/// <summary> /// Open a new or existing socket as a client /// </summary> public static async Task <SocketConnection> ConnectAsync( EndPoint endpoint, PipeOptions sendPipeOptions, PipeOptions receivePipeOptions, SocketConnectionOptions connectionOptions = SocketConnectionOptions.None, Func <SocketConnection, Task> onConnected = null, Socket socket = null, string name = null) { AssertDependencies(); var addressFamily = endpoint.AddressFamily == AddressFamily.Unspecified ? AddressFamily.InterNetwork : endpoint.AddressFamily; var protocolType = addressFamily == AddressFamily.Unix ? ProtocolType.Unspecified : ProtocolType.Tcp; if (socket == null) { socket = new Socket(addressFamily, SocketType.Stream, protocolType); } if (sendPipeOptions == null) { sendPipeOptions = PipeOptions.Default; } if (receivePipeOptions == null) { receivePipeOptions = PipeOptions.Default; } SetRecommendedClientOptions(socket); using (var args = new SocketAwaitableEventArgs((connectionOptions & SocketConnectionOptions.InlineConnect) == 0 ? PipeScheduler.ThreadPool : null)) { args.RemoteEndPoint = endpoint; Helpers.DebugLog(name, $"connecting to {endpoint}..."); if (!socket.ConnectAsync(args)) { args.Complete(); } await args; } Helpers.DebugLog(name, "connected"); var connection = Create(socket, sendPipeOptions, receivePipeOptions, connectionOptions, name); if (onConnected != null) { await onConnected(connection).ConfigureAwait(false); } return(connection); }
private async Task DoReceiveAsync() { Exception error = null; DebugLog("starting receive loop"); try { _readerArgs = new SocketAwaitableEventArgs(InlineReads ? null : _receiveOptions.WriterScheduler); while (true) { if (ZeroLengthReads && Socket.Available == 0) { DebugLog($"awaiting zero-length receive..."); Helpers.Incr(Counter.OpenReceiveReadAsync); DoReceive(Socket, _readerArgs, default, Name);
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)) { Helpers.Incr(Counter.SocketPipeReadReadSync); } else { Helpers.Incr(Counter.OpenSendReadAsync); var read = _sendToSocket.Reader.ReadAsync(); Helpers.Incr(read.IsCompleted ? Counter.SocketPipeReadReadSync : Counter.SocketPipeReadReadAsync); result = await read; Helpers.Decr(Counter.OpenSendReadAsync); } var buffer = result.Buffer; if (result.IsCanceled || (result.IsCompleted && buffer.IsEmpty)) { DebugLog(result.IsCanceled ? "cancelled" : "complete"); break; } try { if (!buffer.IsEmpty) { if (_writerArgs == null) { _writerArgs = new SocketAwaitableEventArgs(InlineWrites ? null : _sendOptions.ReaderScheduler); } DebugLog($"sending {buffer.Length} bytes over socket..."); Helpers.Incr(Counter.OpenSendWriteAsync); DoSend(Socket, _writerArgs, buffer, Name); Helpers.Incr(_writerArgs.IsCompleted ? Counter.SocketSendAsyncSync : Counter.SocketSendAsyncAsync); BytesSent += await _writerArgs; Helpers.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(ex.SocketErrorCode == SocketError.OperationAborted) { TrySetShutdown(PipeShutdownKind.WriteSocketError, ex.SocketErrorCode); DebugLog($"fail: {ex.SocketErrorCode}"); error = null; } catch (SocketException ex) { TrySetShutdown(PipeShutdownKind.WriteSocketError, ex.SocketErrorCode); DebugLog($"fail: {ex.SocketErrorCode}"); error = ex; } catch (ObjectDisposedException) { TrySetShutdown(PipeShutdownKind.WriteDisposed); DebugLog("fail: disposed"); error = null; } catch (IOException ex) { TrySetShutdown(PipeShutdownKind.WriteIOException); DebugLog($"fail - io: {ex.Message}"); error = ex; } catch (Exception ex) { TrySetShutdown(PipeShutdownKind.WriteException); DebugLog($"fail: {ex.Message}"); error = new IOException(ex.Message, ex); } finally { // Make sure to close the connection only after the _aborted flag is set. // Without this, the RequestsCanBeAbortedMidRead test will sometimes fail when // a BadHttpRequestException is thrown instead of a TaskCanceledException. _sendAborted = true; try { DebugLog($"shutting down socket-send"); Socket.Shutdown(SocketShutdown.Send); } catch { } // 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 { } var args = _writerArgs; _writerArgs = null; if (args != null) { try { args.Dispose(); } catch { } } } DebugLog(error == null ? "exiting with success" : $"exiting with failure: {error.Message}"); //return error; }
private static void DoSend(Socket socket, SocketAwaitableEventArgs args, in ReadOnlySequence <byte> buffer, string name)