private void StartSend(SocketAsyncEventArgs args) { if (args.SocketError == SocketError.OperationAborted || Thread.VolatileRead(ref _disposed) == 1) { _sendPool.Push(args); return; } args.Completed += AsyncOperationCompleted; var token = (MessageSendToken)args.UserToken; // If still we have bytes to send. if (token.SendRemaining > 0) { // If message larger than buffer size. if (token.SendRemaining > Settings.BufferSize) { Buffer.BlockCopy(token.Body, token.SendOffset, args.Buffer, args.Offset, Settings.BufferSize); } // Else resize buffer count. else { Buffer.BlockCopy(token.Body, token.SendOffset, args.Buffer, args.Offset, token.SendRemaining); args.SetBuffer(args.Offset, token.SendRemaining); } } if (!Socket.SendAsync(args)) { ProcessSend(args); } }
/// <summary> /// Initializes a new instance of the <see cref="NetworkManagerAsyncSettings"/> class /// with the specified number of receive operation <see cref="SocketAsyncEventArgs"/> objects /// and the specified number of send operation <see cref="SocketAsyncEventArgs"/> objects with /// the specified buffer size of each <see cref="SocketAsyncEventArgs"/> object. /// </summary> /// <param name="receiveCount">Number of receive operation <see cref="SocketAsyncEventArgs"/> objects.</param> /// <param name="sendCount">Number of send operation <see cref="SocketAsyncEventArgs"/> objects.</param> /// <param name="bufferSize">Buffer size of each <see cref="SocketAsyncEventArgs"/> object.</param> /// <exception cref="ArgumentOutOfRangeException"><paramref name="bufferSize"/> less than 1.</exception> public NetworkManagerAsyncSettings(int receiveCount, int sendCount, int bufferSize) { if (bufferSize < 1) { throw new ArgumentOutOfRangeException(nameof(bufferSize), "Buffer size cannot be less than 1."); } _bufferSize = bufferSize; _statistics = new NetworkManagerAsyncStatistics(); // Don't waste IO threads. var concurrentOpsCount = Environment.ProcessorCount * 2; _concurrentOps = new Semaphore(concurrentOpsCount, concurrentOpsCount); _receivePool = new SocketAsyncEventArgsPool(receiveCount); _sendPool = new SocketAsyncEventArgsPool(sendCount); _bufferManager = new MessageBufferManager(receiveCount, sendCount, bufferSize); for (int i = 0; i < ReceiveCount; i++) { var args = new SocketAsyncEventArgs(); _bufferManager.SetBuffer(args); MessageReceiveToken.Create(args); _receivePool.Push(args); } for (int i = 0; i < SendCount; i++) { var args = new SocketAsyncEventArgs(); _bufferManager.SetBuffer(args); MessageSendToken.Create(args); _sendPool.Push(args); } _buffers = new Pool <byte[]>(64); _args = new Pool <SocketAsyncEventArgs>(receiveCount + sendCount); }
private void AsyncOperationCompleted(object sender, SocketAsyncEventArgs args) { // Semaphore timeout. const int TIMEOUT = 5000; args.Completed -= AsyncOperationCompleted; if (Settings._concurrentOps.WaitOne(TIMEOUT)) { // Return the SocketAsyncEventArgs object back to its corresponding pool if // the NetworkManagerAsync was disconnected purposely or disposed. if (args.SocketError == SocketError.OperationAborted || Thread.VolatileRead(ref _disposed) == 1) { switch (args.LastOperation) { case SocketAsyncOperation.Receive: _receivePool.Push(args); break; case SocketAsyncOperation.Send: _sendPool.Push(args); break; } Settings._concurrentOps.Release(); return; } if (args.BytesTransferred == 0 || args.SocketError != SocketError.Success) { switch (args.LastOperation) { case SocketAsyncOperation.Receive: _receivePool.Push(args); break; case SocketAsyncOperation.Send: _sendPool.Push(args); break; } Settings._concurrentOps.Release(); OnDisconnected(new DisconnectedEventArgs(args.SocketError)); return; } switch (args.LastOperation) { case SocketAsyncOperation.Receive: ProcessReceive(args); break; case SocketAsyncOperation.Send: ProcessSend(args); break; default: throw new InvalidOperationException("IMPOSSIBRU! Unexpected SocketAsyncOperation: " + args.LastOperation); } Settings._concurrentOps.Release(); } else { Console.WriteLine("Semaphore not responding in time."); Debug.WriteLine("Semaphore not responding in time."); //TODO: Might want drop connection and release the semaphore. } }