/// <summary> /// Callback for when data is available for reading from the underlying stream. /// </summary> /// <param name="asyncResult">The async result from the read.</param> private void ReadComplete(IAsyncResult asyncResult) { int bytesRead; var dataStream = (NetworkStream)asyncResult.AsyncState; try { if (tcpClient.Connected && dataStream.CanRead && dataStream.DataAvailable) { bytesRead = dataStream.EndRead(asyncResult); if (bytesRead == 1) { var messageBytes = new Collection <byte>(); messageBytes.Add(headerByte[0]); Collection <byte> lengthBytes = MqttHeader.ReadLengthBytes(dataStream); int length = MqttHeader.CalculateLength(lengthBytes); messageBytes.AddRange(lengthBytes); // we've got the bytes that make up the header, inc the size, read the . var remainingMessage = new byte[length]; int messageBytesRead = dataStream.Read(remainingMessage, 0, length); if (messageBytesRead < length) { // we haven't got all the message, need to figure oput what to do. } messageBytes.AddRange(remainingMessage); FireDataAvailableEvent(messageBytes); } } // initiate a read for the next byte which will be the header bytes so long as // we're still connected to the underlying client if (tcpClient.Connected && networkStream.CanRead) { dataStream.BeginRead(headerByte, 0, 1, ReadComplete, dataStream); } } catch (IOException ex) { // close the underlying connection this.Disconnect(); if (ConnectionDropped != null) { ConnectionDropped(this, new ConnectionDroppedEventArgs(ex)); } } }
/// <summary> /// Callback for when data has been read from the underlying network stream. /// </summary> /// <param name="asyncResult">The async result from the read.</param> private void ReadHeaderComplete(IAsyncResult asyncResult) { var readWrapper = (ReadWrapper)asyncResult.AsyncState; try { var bytesRead = readWrapper.Stream.EndRead(asyncResult); if (bytesRead == 0) { // Nothing read, we will just try another read from the stream. Log.Debug("Async network stream read returned 0 bytes, continuing to search for header."); readWrapper.ReadState = ConnectionReadState.Header; } else if (tcpClient.Connected && readWrapper.Stream.CanRead) { if (readWrapper.ReadState == ConnectionReadState.Header && readWrapper.Stream.DataAvailable) { Log.Info("Reading message arriving on the wire."); readWrapper.MessageBytes.Add(readWrapper.Buffer[0]); var lengthBytes = MqttHeader.ReadLengthBytes(readWrapper.Stream); var remainingLength = MqttHeader.CalculateLength(lengthBytes); // update the read wrapper with the header bytes, and a resized read buffer // to capture the remaining length. readWrapper.MessageBytes.AddRange(lengthBytes); // no content, so yield the message early, else transition to reading the content. if (remainingLength == 0) { Log.Debug("Message receipt complete. Has empty content length so handing off now."); FireDataAvailableEvent(readWrapper.MessageBytes); } else { // total bytes of content is the remaining length plus the header. readWrapper.TotalBytes = remainingLength + readWrapper.MessageBytes.Count; readWrapper.RecalculateNextReadSize(); readWrapper.ReadState = ConnectionReadState.Content; } } else if (readWrapper.ReadState == ConnectionReadState.Content) { // stash what we've read. readWrapper.MessageBytes.AddRange(readWrapper.Buffer.Take(bytesRead)); Log.Debug(m => m("Message Content read {0:n0} of {1:n0} expected remaining bytes.", bytesRead, readWrapper.TotalBytes)); // if we haven't yet read all of the message repeat the read otherwise if // we're finished process the message and switch back to waiting for the next header. if (readWrapper.IsReadComplete) { // reset the read buffer to accommodate the remaining length (last - what was read) readWrapper.RecalculateNextReadSize(); } else { Log.Debug(m => m("Message receipt complete ({0:n0} total bytes including all headers), handing off to handlers.", readWrapper.MessageBytes.Count)); readWrapper.ReadState = ConnectionReadState.Header; FireDataAvailableEvent(readWrapper.MessageBytes); } } // if we've switched to reading a header then recreate the read dwrapper for the next message if (readWrapper.ReadState == ConnectionReadState.Header) { readWrapper = new ReadWrapper(readWrapper.Stream); } // we can still read etc // initiate a read for the next set of bytes which will be the header bytes so long as // we're still connected to the underlying client readWrapper.Stream.BeginRead(readWrapper.Buffer, 0, readWrapper.NextReadSize, ReadHeaderComplete, readWrapper); } } catch (IOException ex) { Log.Debug("Error occurred during async read from broker network stream. Initiating broker disconnect", ex); // close the underlying connection this.Disconnect(); if (ConnectionDropped != null) { ConnectionDropped(this, new ConnectionDroppedEventArgs(ex)); } } }