private void ReceiveBuffer(int receiveCount) { // TCP guarantees delivery of all packets in the correct order. // But there is no guarantee that one write operation on the sender-side will result in // one read event on the receiving side. One call of write(message) by the sender // can result in multiple messageReceived(session, message) events on the receiver; // and multiple calls of write(message) can lead to a single messageReceived event. // In a stream-based transport such as TCP/IP, received data is stored into a socket receive buffer. // Unfortunately, the buffer of a stream-based transport is not a queue of packets but a queue of bytes. // It means, even if you sent two messages as two independent packets, // an operating system will not treat them as two messages but as just a bunch of bytes. // Therefore, there is no guarantee that what you read is exactly what your remote peer wrote. // There are three common techniques for splitting the stream of bytes into messages: // 1. use fixed length messages // 2. use a fixed length header that indicates the length of the body // 3. using a delimiter; for example many text-based protocols append // a newline (or CR LF pair) after every message. int frameLength; byte[] payload; int payloadOffset; int payloadCount; int consumedLength = 0; SegmentBufferDeflector.ReplaceBuffer(_bufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); while (true) { frameLength = 0; payload = null; payloadOffset = 0; payloadCount = 0; if (_configuration.FrameBuilder.Decoder.TryDecodeFrame( _receiveBuffer.Array, _receiveBuffer.Offset + consumedLength, _receiveBufferOffset - consumedLength, out frameLength, out payload, out payloadOffset, out payloadCount)) { try { _server.RaiseClientDataReceived(this, payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } finally { consumedLength += frameLength; } } else { break; } } SegmentBufferDeflector.ShiftBuffer(_bufferManager, consumedLength, ref _receiveBuffer, ref _receiveBufferOffset); }
private async Task Process() { try { int frameLength; byte[] payload; int payloadOffset; int payloadCount; int consumedLength = 0; while (State == TcpSocketConnectionState.Connected) { int receiveCount = await _stream.ReadAsync( _receiveBuffer.Array, _receiveBuffer.Offset + _receiveBufferOffset, _receiveBuffer.Count - _receiveBufferOffset); if (receiveCount == 0) { break; } SegmentBufferDeflector.ReplaceBuffer(_bufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); consumedLength = 0; while (true) { frameLength = 0; payload = null; payloadOffset = 0; payloadCount = 0; if (_configuration.FrameBuilder.Decoder.TryDecodeFrame( _receiveBuffer.Array, _receiveBuffer.Offset + consumedLength, _receiveBufferOffset - consumedLength, out frameLength, out payload, out payloadOffset, out payloadCount)) { try { await _dispatcher.OnSessionDataReceived(this, payload, payloadOffset, payloadCount); } catch (Exception ex) // catch all exceptions from out-side { await HandleUserSideError(ex); } finally { consumedLength += frameLength; } } else { break; } } if (_receiveBuffer != null && _receiveBuffer.Array != null) { SegmentBufferDeflector.ShiftBuffer(_bufferManager, consumedLength, ref _receiveBuffer, ref _receiveBufferOffset); } } } catch (ObjectDisposedException) { // looking forward to a graceful quit from the ReadAsync but the inside EndRead will raise the ObjectDisposedException, // so a gracefully close for the socket should be a Shutdown, but we cannot avoid the Close triggers this happen. } catch (Exception ex) { await HandleReceiveOperationException(ex); } finally { await Close(true); // read async buffer returned, remote notifies closed } }
private async Task Process() { try { int frameLength; byte[] payload; int payloadOffset; int payloadCount; int consumedLength = 0; var saea = _saeaPool.Take(); saea.Saea.SetBuffer(_receiveBuffer.Array, _receiveBuffer.Offset + _receiveBufferOffset, _receiveBuffer.Count - _receiveBufferOffset); while (State == TcpSocketConnectionState.Connected) { saea.Saea.SetBuffer(_receiveBuffer.Array, _receiveBuffer.Offset + _receiveBufferOffset, _receiveBuffer.Count - _receiveBufferOffset); var socketError = await _socket.ReceiveAsync(saea); if (socketError != SocketError.Success) { break; } var receiveCount = saea.Saea.BytesTransferred; if (receiveCount == 0) { break; } SegmentBufferDeflector.ReplaceBuffer(_configuration.BufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); consumedLength = 0; while (true) { frameLength = 0; payload = null; payloadOffset = 0; payloadCount = 0; if (_configuration.FrameBuilder.Decoder.TryDecodeFrame(_receiveBuffer.Array, _receiveBuffer.Offset + consumedLength, _receiveBufferOffset - consumedLength, out frameLength, out payload, out payloadOffset, out payloadCount)) { try { await _dispatcher.OnServerDataReceived(this, payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } finally { consumedLength += frameLength; } } else { break; } } try { SegmentBufferDeflector.ShiftBuffer(_configuration.BufferManager, consumedLength, ref _receiveBuffer, ref _receiveBufferOffset); } catch (ArgumentOutOfRangeException) { } } } catch (Exception ex) when(!ShouldThrow(ex)) { } finally { await Close(); } }
private async Task Process() { try { int frameLength; byte[] payload; int payloadOffset; int payloadCount; int consumedLength = 0; var saea = _saeaPool.Take(); saea.Saea.SetBuffer(_receiveBuffer.Array, _receiveBuffer.Offset + _receiveBufferOffset, _receiveBuffer.Count - _receiveBufferOffset); while (State == TcpSocketConnectionState.Connected) { saea.Saea.SetBuffer(_receiveBuffer.Array, _receiveBuffer.Offset + _receiveBufferOffset, _receiveBuffer.Count - _receiveBufferOffset); var socketError = await _socket.ReceiveAsync(saea); if (socketError != SocketError.Success) { break; } var receiveCount = saea.Saea.BytesTransferred; if (receiveCount == 0) { break; } SegmentBufferDeflector.ReplaceBuffer(_configuration.BufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); consumedLength = 0; while (true) { frameLength = 0; payload = null; payloadOffset = 0; payloadCount = 0; if (_configuration.FrameBuilder.Decoder.TryDecodeFrame(_receiveBuffer.Array, _receiveBuffer.Offset + consumedLength, _receiveBufferOffset - consumedLength, out frameLength, out payload, out payloadOffset, out payloadCount)) { try { await _dispatcher.OnServerDataReceived(this, payload, payloadOffset, payloadCount); } catch (Exception ex) // catch all exceptions from out-side { await HandleUserSideError(ex); } finally { consumedLength += frameLength; } } else { break; } } if (_receiveBuffer != null && _receiveBuffer.Array != null) { SegmentBufferDeflector.ShiftBuffer(_configuration.BufferManager, consumedLength, ref _receiveBuffer, ref _receiveBufferOffset); } } } catch (Exception ex) { await HandleReceiveOperationException(ex); } finally { await Close(true); // read async buffer returned, remote notifies closed } }
private async Task Process() { try { int frameLength; byte[] payload; int payloadOffset; int payloadCount; int consumedLength = 0; while (State == TcpSocketConnectionState.Connected) { int receiveCount = await _stream.ReadAsync(_receiveBuffer.Array, _receiveBuffer.Offset + _receiveBufferOffset, _receiveBuffer.Count - _receiveBufferOffset); if (receiveCount == 0) { break; } SegmentBufferDeflector.ReplaceBuffer(_bufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); consumedLength = 0; while (true) { frameLength = 0; payload = null; payloadOffset = 0; payloadCount = 0; if (_configuration.FrameBuilder.Decoder.TryDecodeFrame( _receiveBuffer.Array, _receiveBuffer.Offset + consumedLength, _receiveBufferOffset - consumedLength, out frameLength, out payload, out payloadOffset, out payloadCount)) { try { await _dispatcher.OnSessionDataReceived(this, payload, payloadOffset, payloadCount); } catch (Exception ex) { await HandleUserSideError(ex); } finally { consumedLength += frameLength; } } else { break; } } SegmentBufferDeflector.ShiftBuffer(_bufferManager, consumedLength, ref _receiveBuffer, ref _receiveBufferOffset); } } catch (Exception ex) { await HandleReceiveOperationException(ex); } finally { await Close(); } }
public async Task Start() { var webSocket = this.Context.WebSocket; ArraySegment <byte> receiveBuffer = _bufferManager.BorrowBuffer(); ArraySegment <byte> sessionBuffer = _bufferManager.BorrowBuffer(); int sessionBufferCount = 0; _log.DebugFormat("Session started for [{0}] on [{1}] in module [{2}] with session count [{3}].", this.RemoteEndPoint, this.StartTime.ToString(@"yyyy-MM-dd HH:mm:ss.fffffff"), this.Module.ModuleName, this.Module.SessionCount); try { while (webSocket.State == WebSocketState.Open) { this.CancellationToken.ThrowIfCancellationRequested(); var receiveResult = await webSocket.ReceiveAsync(receiveBuffer, this.CancellationToken); switch (receiveResult.MessageType) { case WebSocketMessageType.Text: { if (receiveResult.EndOfMessage && sessionBufferCount == 0) { var message = new WebSocketTextMessage(this, this.Encoding.GetString(receiveBuffer.Array, receiveBuffer.Offset, receiveResult.Count)); await this.Module.ReceiveTextMessage(message); } else { SegmentBufferDeflector.AppendBuffer(_bufferManager, ref receiveBuffer, receiveResult.Count, ref sessionBuffer, ref sessionBufferCount); if (receiveResult.EndOfMessage) { var message = new WebSocketTextMessage(this, this.Encoding.GetString(sessionBuffer.Array, sessionBuffer.Offset, sessionBufferCount)); await this.Module.ReceiveTextMessage(message); sessionBufferCount = 0; } } } break; case WebSocketMessageType.Binary: { if (receiveResult.EndOfMessage && sessionBufferCount == 0) { var message = new WebSocketBinaryMessage(this, receiveBuffer.Array, receiveBuffer.Offset, receiveResult.Count); await this.Module.ReceiveBinaryMessage(message); } else { SegmentBufferDeflector.AppendBuffer(_bufferManager, ref receiveBuffer, receiveResult.Count, ref sessionBuffer, ref sessionBufferCount); if (receiveResult.EndOfMessage) { var message = new WebSocketBinaryMessage(this, sessionBuffer.Array, sessionBuffer.Offset, sessionBufferCount); await this.Module.ReceiveBinaryMessage(message); sessionBufferCount = 0; } } } break; case WebSocketMessageType.Close: { await Close( receiveResult.CloseStatus.HasValue?receiveResult.CloseStatus.Value : WebSocketCloseStatus.NormalClosure, receiveResult.CloseStatusDescription); } break; } } } catch (WebSocketException) { } finally { _bufferManager.ReturnBuffer(receiveBuffer); _bufferManager.ReturnBuffer(sessionBuffer); _log.DebugFormat("Session closed for [{0}] on [{1}] in module [{2}] with session count [{3}].", this.RemoteEndPoint, DateTime.UtcNow.ToString(@"yyyy-MM-dd HH:mm:ss.fffffff"), this.Module.ModuleName, this.Module.SessionCount - 1); if (webSocket != null) { webSocket.Dispose(); } } }