private void CloseClientSocket(SocketAsyncEventArgs workerEventArgs) { var token = (DataHoldingUserToken <T>)workerEventArgs.UserToken; // --- Logging / Debugging _trace.ClosingConnection(_settings.CustomState, token, workerEventArgs.GetRemoteIpEndPoint(), token.CloseAfterSend, token.ClosedByClient, token.CloseReason); // --- _watchDog.RemoveWatch(workerEventArgs); // do a shutdown before you close the socket try { workerEventArgs.AcceptSocket.Shutdown(SocketShutdown.Both); } // throws if socket was already closed catch { } //This method closes the socket and releases all resources, both //managed and unmanaged. It internally calls Dispose. workerEventArgs.AcceptSocket.Close(); token.Reset(); _workerPool.Push(workerEventArgs); //Release Semaphore so that its connection counter will be decremented. //This must be done AFTER putting the SocketAsyncEventArg back into the pool, //or you can run into problems. _maxConnectionsEnforcer.Release(); }
/// <summary> /// Setup connection to use a SocketAsyncEventArgs setup to send/Receive /// </summary> /// <param name="acceptEventArgs"></param> private void ProcessAccept(SocketAsyncEventArgs acceptEventArgs) { IdentityUserToken token = (IdentityUserToken)acceptEventArgs.UserToken; token.LastTalked = ServerDiagnostics.Instance.Now; // Handle failure to accept connection if (acceptEventArgs.SocketError != SocketError.Success) { StartAccept(); HandleBadAccept(acceptEventArgs, acceptEventArgs.SocketError); return; } _trace.HandleAccept(_settings.CustomState, token, acceptEventArgs.GetRemoteIpEndPoint()); // Begin listening for more connections StartAccept(); var workerEventArgs = GetWorkerFromAcceptEventArgs(acceptEventArgs); _watchDog.AddWatch(workerEventArgs); StartReceive(workerEventArgs); }
/// <summary> /// Begin sending data /// </summary> /// <param name="workerEventArgs"></param> private void StartSend(SocketAsyncEventArgs workerEventArgs) { DataHoldingUserToken <T> token = (DataHoldingUserToken <T>)workerEventArgs.UserToken; if (token.WriteDataBytesRemaining <= _settings.IoBufferSize) { // Whole remaining message will fit in buffer. workerEventArgs.SetBuffer(token.WriteBufferOffset, token.WriteDataBytesRemaining); Buffer.BlockCopy(token.WriteData, token.WriteDataBytesSent, workerEventArgs.Buffer, token.WriteBufferOffset, token.WriteDataBytesRemaining); // --- Logging / Debugging _trace.Sending(_settings.CustomState, token, workerEventArgs.GetRemoteIpEndPoint(), workerEventArgs.Buffer, token.WriteBufferOffset, token.WriteDataBytesRemaining); // --- } else { // Message to big to all go in buffer. workerEventArgs.SetBuffer(token.WriteBufferOffset, _settings.IoBufferSize); Buffer.BlockCopy(token.WriteData, token.WriteDataBytesSent, workerEventArgs.Buffer, token.WriteBufferOffset, _settings.IoBufferSize); // We update the token.WriteDataBytesSent once the Sending has been confirmed. // --- Logging / Debugging _trace.Sending(_settings.CustomState, token, workerEventArgs.GetRemoteIpEndPoint(), workerEventArgs.Buffer, token.WriteBufferOffset, _settings.IoBufferSize); // --- } bool runningAsync = workerEventArgs.AcceptSocket.SendAsync(workerEventArgs); if (!runningAsync) { ProcessSend(workerEventArgs); } }
private void ProcessSend(SocketAsyncEventArgs workerEventArgs) { DataHoldingUserToken <T> token = (DataHoldingUserToken <T>)workerEventArgs.UserToken; token.WriteDataBytesSent += workerEventArgs.BytesTransferred; // --- Logging / Debugging _trace.Sent(_settings.CustomState, token, workerEventArgs.GetRemoteIpEndPoint(), workerEventArgs.BytesTransferred); // --- if (workerEventArgs.SocketError != SocketError.Success) { token.Reset(); CloseClientSocket(workerEventArgs); return; } if (token.WriteDataBytesRemaining > 0) { // If some of the bytes in the message have NOT been sent, // then we will need to post another send operation StartSend(workerEventArgs); } else { if (token.CloseAfterSend) { CloseClientSocket(workerEventArgs); } else { StartReceive(workerEventArgs); } } }
private void ProcessReceive(SocketAsyncEventArgs workerEventArgs) { var token = (DataHoldingUserToken <T>)workerEventArgs.UserToken; token.ReceivedBytes += workerEventArgs.BytesTransferred; token.LastTalked = ServerDiagnostics.Instance.Now; // Check the socket is still good bool closeSocket = workerEventArgs.BytesTransferred == 0 || // Client has closed the connection (Normal) workerEventArgs.SocketError != SocketError.Success || // Something has gone wrong. (Bad) token.ReceivedBytes > token.BufferSize; // Recieved more data then we can handle (Bad) // if not close the socket if (closeSocket) { if (token.ReceivedBytes > token.BufferSize && workerEventArgs.SocketError == SocketError.Success) { _trace.ReceivedGreaterThanBuffer(_settings.CustomState, token, workerEventArgs.GetRemoteIpEndPoint(), workerEventArgs.Buffer, token.ReceiveBufferOffset, token.ReceivedBytes); } //token.Reset(); token.ClosedByClient = workerEventArgs.BytesTransferred == 0; token.CloseReason = workerEventArgs.SocketError; CloseClientSocket(workerEventArgs); return; } //Create a clone of the endpoint, as having a task might mean accessing the socket details after the endpoint is no longer valid. var currentEndpoint = workerEventArgs.GetRemoteIpEndPoint(); IPEndPoint ipEndPoint = new IPEndPoint(currentEndpoint.Address, currentEndpoint.Port); // --- Logging / Debugging _trace.Received(_settings.CustomState, token, ipEndPoint, workerEventArgs.Buffer, token.ReceiveBufferOffset, token.ReceivedBytes); // --- // Check if we have a full message bool incomingMessageReady = _messageHandler.IsMessageComplete(workerEventArgs.Buffer, token.ReceiveBufferOffset, token.ReceivedBytes, workerEventArgs.BytesTransferred, token.SocketStateData); if (incomingMessageReady) { // If so handle it, and send a response // if we have one // --- Logging / Debugging _trace.QueuedTask(_settings.CustomState, token); // --- var requestStartTime = DateTime.Now; _taskManager.StartNew(state => { SocketListenerState s = (SocketListenerState)state; try { // --- Logging / Debugging _trace.StartingTask(_settings.CustomState, token, requestStartTime); // --- if ((DateTime.Now - requestStartTime).TotalSeconds > _settings.MaxTaskDelay) { _trace.ExpiredTask(_settings.CustomState, token); CloseClientSocket(workerEventArgs); return; } var response = _messageHandler.HandleMessage(s.EndPoint, workerEventArgs.Buffer, token.ReceiveBufferOffset, token.ReceivedBytes, _settings.CustomState, token.SocketStateData); token.Reset(); token.WriteData = response.ToSend; token.CloseAfterSend = response.DisconnectOnceDone; if (token.WriteData != null) { StartSend(workerEventArgs); } else if (response.DisconnectOnceDone) { CloseClientSocket(workerEventArgs); } else { StartReceive(workerEventArgs); } // --- Logging / Debugging _trace.CompletedTask(_settings.CustomState, token); // --- } catch (Exception e) { // Task failed... _trace.FailedTask(_settings.CustomState, token, e); CloseClientSocket(workerEventArgs); } }, new SocketListenerState { EndPoint = ipEndPoint }); } else { // otherwise wait for more data to be recieved StartReceive(workerEventArgs); } }
private void HandleBadAccept(SocketAsyncEventArgs acceptEventArgs, SocketError error) { // --- Logging / Debugging _trace.HandleBadAccept(_settings.CustomState, (IdentityUserToken)acceptEventArgs.UserToken, acceptEventArgs.GetRemoteIpEndPoint(), error); // --- acceptEventArgs.AcceptSocket.Close(); acceptEventArgs.AcceptSocket = null; _acceptPool.Push(acceptEventArgs); }