/// <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, ILogger logger = null) { 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); logger = logger ?? NullLoggerFactory.Instance.CreateLogger("NetGear.Core.SocketConnection"); using (var args = new SocketAwaitableEventArgs((connectionOptions & SocketConnectionOptions.InlineConnect) == 0 ? PipeScheduler.ThreadPool : null)) { args.RemoteEndPoint = endpoint; _logger.LogVerbose(name, $"connecting to {endpoint}..."); if (!socket.ConnectAsync(args)) { args.Complete(); } await args; } _logger.LogVerbose(name, "connected"); var connection = Create(socket, sendPipeOptions, receivePipeOptions, connectionOptions, name, logger); if (onConnected != null) { await onConnected(connection).ConfigureAwait(false); } return(connection); }
private async Task DoReceiveAsync() { Exception error = null; DebugLog("starting receive loop"); try { // 说明:recv方向上是recv from socket and push to pipe,所以这里回调应该是 // 执行在WriterScheduler上 _readerArgs = new SocketAwaitableEventArgs(InlineReads ? null : _receiveOptions.WriterScheduler); while (true) { if (ZeroLengthReads && Socket.Available == 0) { DebugLog($"awaiting zero-length receive..."); CounterHelper.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)) { 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}"); }
private void DoSend(Socket socket, SocketAwaitableEventArgs args, in ReadOnlySequence <byte> buffer, string name)