/// <summary> /// 释放资源。 /// </summary> /// <param name="disposing">释放资源标记。</param> private void Dispose(bool disposing) { if (m_Disposed) { return; } if (disposing) { Close(); m_SendState.Dispose(); m_ReceiveState.Dispose(); } m_Disposed = true; }
/// <summary> /// 释放资源。 /// </summary> /// <param name="disposing">释放资源标记。</param> private void Dispose(bool disposing) { if (m_Disposed) { return; } if (disposing) { Close(); m_SendState.Dispose(); m_ReceiveState.Dispose(); NetworkChannelConnected = null; NetworkChannelClosed = null; NetworkChannelMissHeartBeat = null; NetworkChannelError = null; NetworkReceive = null; } m_Disposed = true; }
private void ProcessIntegratedSecurityAuthentication(IAsyncResult asyncResult) { ConnectState connectState = null; ReceiveState receiveState = null; SendState sendState = null; try { // Get the connect state from the async result connectState = (ConnectState)asyncResult.AsyncState; // Quit if this connection loop has been cancelled if (connectState.Token.Cancelled) return; try { // Complete the operation to authenticate with the server connectState.NegotiateStream.EndAuthenticateAsClient(asyncResult); } catch (InvalidCredentialException) { if (!m_ignoreInvalidCredentials) throw; } // Initialize the SocketAsyncEventArgs for receive operations connectState.ReceiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); connectState.ReceiveArgs.SetBuffer(new byte[ReceiveBufferSize], 0, ReceiveBufferSize); if (m_payloadAware) connectState.ReceiveArgs.Completed += (sender, args) => ProcessReceivePayloadAware((ReceiveState)args.UserToken); else connectState.ReceiveArgs.Completed += (sender, args) => ProcessReceivePayloadUnaware((ReceiveState)args.UserToken); // Initialize the SocketAsyncEventArgs for send operations connectState.SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); connectState.SendArgs.SetBuffer(new byte[SendBufferSize], 0, SendBufferSize); connectState.SendArgs.Completed += (sender, args) => ProcessSend((SendState)args.UserToken); // Initialize state object for the asynchronous send loop sendState = new SendState(); sendState.Token = connectState.Token; sendState.Socket = connectState.Socket; sendState.ReceiveArgs = connectState.ReceiveArgs; sendState.SendArgs = connectState.SendArgs; sendState.SendArgs.UserToken = sendState; // Store sendState in m_sendState so that calls to Disconnect // and Dispose can dispose resources and cancel asynchronous loops m_sendState = sendState; // Check the state of cancellation one more time before // proceeding to the next step of the connection loop if (connectState.Token.Cancelled) return; // Notify of established connection // and begin receiving data. m_connectWaitHandle.Set(); OnConnectionEstablished(); // Initialize state object for the asynchronous receive loop receiveState = new ReceiveState(); receiveState.Token = connectState.Token; receiveState.Socket = connectState.Socket; receiveState.Buffer = connectState.ReceiveArgs.Buffer; receiveState.ReceiveArgs = connectState.ReceiveArgs; receiveState.ReceiveArgs.UserToken = receiveState; receiveState.SendArgs = connectState.SendArgs; // Store receiveState in m_receiveState so that calls to Disconnect // and Dispose can dispose resources and cancel asynchronous loops m_receiveState = receiveState; // Start receiving data if (m_payloadAware) ReceivePayloadAwareAsync(receiveState); else ReceivePayloadUnawareAsync(receiveState); // Further socket interactions are handled through the SslStream // object, so the SocketAsyncEventArgs is no longer needed connectState.ConnectArgs.Dispose(); } catch (SocketException ex) { // Log exception during connection attempt OnConnectionException(ex); // If connectState is null, we cannot proceed if ((object)connectState == null) return; // If the connection is refused by the server, // keep trying until we reach our maximum connection attempts if (ex.SocketErrorCode == SocketError.ConnectionRefused && (MaxConnectionAttempts == -1 || connectState.ConnectionAttempts < MaxConnectionAttempts)) { try { ConnectAsync(connectState); } catch { TerminateConnection(connectState.Token); } } else { // For any other socket exception, // terminate the connection TerminateConnection(connectState.Token); } } catch (Exception ex) { // Log exception during connection attempt string errorMessage = $"Unable to authenticate connection to server: {ex.Message}"; OnConnectionException(new Exception(errorMessage, ex)); // Terminate the connection if ((object)connectState != null) TerminateConnection(connectState.Token); } finally { if ((object)connectState != null) { // If the operation was cancelled during execution, // make sure to dispose of erroneously allocated resources; // otherwise, dispose of the NegotiateStream which is only used for authentication if (connectState.Token.Cancelled) { connectState.Dispose(); } else { connectState.NetworkStream.Dispose(); connectState.NegotiateStream.Dispose(); } } if ((object)receiveState != null && receiveState.Token.Cancelled) receiveState.Dispose(); if ((object)sendState != null && sendState.Token.Cancelled) sendState.Dispose(); } }
/// <summary> /// Callback method for asynchronous send operation. /// </summary> private void ProcessSend(SendState sendState) { TcpClientPayload payload; ManualResetEvent handle = null; try { // Get the payload and its wait handle. payload = sendState.Payload; handle = payload.WaitHandle; // Quit if this send loop has been cancelled if (sendState.Token.Cancelled) return; // Determine if the server disconnected gracefully if (!sendState.Socket.Connected) throw new SocketException((int)SocketError.Disconnecting); // Check for errors during send operation if (sendState.SendArgs.SocketError != SocketError.Success) throw new SocketException((int)sendState.SendArgs.SocketError); try { // Set the wait handle to indicate // the send operation has finished handle.Set(); } catch (ObjectDisposedException) { // Ignore if the consumer has // disposed of the wait handle } // Update statistics and notify that the send operation is complete UpdateBytesSent(sendState.SendArgs.BytesTransferred); OnSendDataComplete(); } catch (ObjectDisposedException) { // Make sure connection is terminated when client is disposed TerminateConnection(sendState.Token); } catch (SocketException ex) { // Log exception during send operation OnSendDataException(ex); // Terminate connection when socket exception is encountered TerminateConnection(sendState.Token); } catch (Exception ex) { // For any other exception, notify and resume OnSendDataException(ex); } finally { // If the operation was cancelled during execution, // make sure to dispose of allocated resources if ((object)sendState != null && sendState.Token.Cancelled) sendState.Dispose(); try { // Make sure to set the wait handle // even if an exception occurs if ((object)handle != null) handle.Set(); } catch (ObjectDisposedException) { // Ignore if the consumer has // disposed of the wait handle } // Attempt to send the next payload SendPayloadAsync(sendState); } }
/// <summary> /// Sends a payload on the socket. /// </summary> private void SendPayloadAsync(SendState sendState) { TcpClientPayload payload; try { // Quit if this send loop has been cancelled if (sendState.Token.Cancelled) return; if (sendState.SendQueue.TryDequeue(out payload)) { // Save the payload currently // being sent to the send state sendState.Payload = payload; // Ensure that the payload fits in the send buffer if (payload.Length > sendState.SendArgs.Buffer.Length) sendState.SendArgs.SetBuffer(new byte[payload.Length], 0, payload.Length); else sendState.SendArgs.SetBuffer(0, payload.Length); // Copy payload into send buffer Buffer.BlockCopy(payload.Data, payload.Offset, sendState.SendArgs.Buffer, 0, payload.Length); // Send payload to the client asynchronously if (!sendState.Socket.SendAsync(sendState.SendArgs)) ThreadPool.QueueUserWorkItem(state => ProcessSend((SendState)state), sendState); } else { // No more payloads to send, so stop sending payloads Interlocked.Exchange(ref sendState.Sending, 0); // Double-check to ensure that a new payload didn't appear before exiting the send loop if (!sendState.SendQueue.IsEmpty && Interlocked.CompareExchange(ref sendState.Sending, 1, 0) == 0) ThreadPool.QueueUserWorkItem(state => SendPayloadAsync((SendState)state), sendState); } } catch (Exception ex) { // Log exception during send operation OnSendDataException(ex); // Continue asynchronous send loop ThreadPool.QueueUserWorkItem(state => SendPayloadAsync((SendState)state), sendState); } finally { // If the operation was cancelled during execution, // make sure to dispose of allocated resources if (sendState.Token.Cancelled) sendState.Dispose(); } }
/// <summary> /// Sends a payload on the socket. /// </summary> private void SendPayloadAsync(SendState sendState) { TlsClientPayload payload; byte[] data; int offset; int length; try { // Quit if this send loop has been cancelled if (sendState.Token.Cancelled) return; if (sendState.SendQueue.TryDequeue(out payload)) { // Save the payload currently // being sent to the send state sendState.Payload = payload; data = payload.Data; offset = payload.Offset; length = payload.Length; // Send payload to the client asynchronously. sendState.SslStream.BeginWrite(data, offset, length, ProcessSend, sendState); } else { // No more payloads to send, so stop sending payloads Interlocked.Exchange(ref sendState.Sending, 0); // Double-check to ensure that a new payload didn't appear before exiting the send loop if (!sendState.SendQueue.IsEmpty && Interlocked.CompareExchange(ref sendState.Sending, 1, 0) == 0) ThreadPool.QueueUserWorkItem(state => SendPayloadAsync((SendState)state), sendState); } } catch (Exception ex) { // Log exception during send operation OnSendDataException(ex); // Continue asynchronous send loop ThreadPool.QueueUserWorkItem(state => SendPayloadAsync((SendState)state), sendState); } finally { // If the operation was cancelled during execution, // make sure to dispose of allocated resources if (sendState.Token.Cancelled) sendState.Dispose(); } }