private async Task Process() { try { int frameLength; byte[] payload; int payloadOffset; int payloadCount; while (State == TcpSocketConnectionState.Connected) { int receiveCount = await _stream.ReadAsync(_receiveBuffer, 0, _receiveBuffer.Length); if (receiveCount == 0) { break; } BufferDeflector.AppendBuffer(_bufferManager, ref _receiveBuffer, receiveCount, ref _sessionBuffer, ref _sessionBufferCount); while (true) { if (_configuration.FrameBuilder.TryDecodeFrame(_sessionBuffer, _sessionBufferCount, out frameLength, out payload, out payloadOffset, out payloadCount)) { try { await _dispatcher.OnSessionDataReceived(this, payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } finally { BufferDeflector.ShiftBuffer(_bufferManager, frameLength, ref _sessionBuffer, ref _sessionBufferCount); #if DEBUG _log.DebugFormat("Session [{0}] buffer length [{1}].", this, _sessionBufferCount); #endif } } else { break; } } } } catch (Exception ex) when(!ShouldThrow(ex)) { } finally { await Close(); } }
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; BufferDeflector.AppendBuffer(_bufferManager, ref _receiveBuffer, receiveCount, ref _sessionBuffer, ref _sessionBufferCount); while (true) { if (_configuration.FrameBuilder.TryDecodeFrame(_sessionBuffer, _sessionBufferCount, out frameLength, out payload, out payloadOffset, out payloadCount)) { try { RaiseServerDataReceived(payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } finally { BufferDeflector.ShiftBuffer(_bufferManager, frameLength, ref _sessionBuffer, ref _sessionBufferCount); #if DEBUG _log.DebugFormat("Session [{0}] buffer length [{1}].", this, _sessionBufferCount); #endif } } else { break; } } }