private void OnPayloadReceived(IAsyncResult result) { ReadAttachment attachment = (ReadAttachment)result.AsyncState; // Keep track of how many bytes we have read, notice the + sign attachment.NumberOfBytesReadSoFar += (ulong)ClientSocket.EndReceive(result); if (attachment.NumberOfBytesReadSoFar > 0) { // If we are here that means the Header was already Read // A common bug is to do if(NumberOfBytesReadSoFar < ReceivingPayloadBuffer.Length) // that is wrong when reusing the ReceivingPayloadBuffer (which we are in this case) // because what would happen if wew are reusing a payload buffer bigger than // the currently expected payload size? well, you guessed it, we would be mixing // to packets in the same buffer... if (attachment.NumberOfBytesReadSoFar < attachment.ExpectedReceivingPayloadLength) { // If we have not filled the buffer that means we have to keep reading // Obviously we don't want to override what we have read so far, so adjust // the offset, and also the length because now we have to take into account // what we have read so far ClientSocket.BeginReceive(attachment.ReceivingPayloadBuffer, (int)attachment.NumberOfBytesReadSoFar, // Offset (int)((ulong)attachment.ReceivingPayloadBuffer.LongLength - attachment.NumberOfBytesReadSoFar), SocketFlags.None, OnPayloadReceived, attachment); } else { IFormatter formatter = new BinaryFormatter(); MemoryStream memoryStream = new MemoryStream(attachment.ReceivingPayloadBuffer); Packet packet = (Packet)formatter.Deserialize(memoryStream); attachment.NumberOfBytesReadSoFar = 0; // Empty the byte[] arrays, this is actually not needed, but it is a good practice Array.Clear(attachment.ReceivingHeaderBuffer, 0, attachment.ReceivingHeaderBuffer.Length); Array.Clear(attachment.ReceivingPayloadBuffer, 0, attachment.ReceivingPayloadBuffer.Length); // Read another packet ReadHeader(); OnPacketReceived(packet); } } else { // This most likely means socket closed Console.WriteLine("Read 0 bytes"); } }
private void OnHeaderReceived(IAsyncResult result) { try { ReadAttachment attachment = (ReadAttachment)result.AsyncState; // Keep track of how many bytes we have read, notice the + sign attachment.NumberOfBytesReadSoFar += (ulong)ClientSocket.EndReceive(result); if (attachment.NumberOfBytesReadSoFar > 0) { if (attachment.NumberOfBytesReadSoFar == (ulong)attachment.ReceivingHeaderBuffer.Length) { // We have read the header, now let's proceed to read the payload // Reset this, because we are gonna use it // to keep track of number of bytes read for the payload, instead of Header attachment.NumberOfBytesReadSoFar = 0; attachment.ExpectedReceivingPayloadLength = BitConverter.ToUInt64(attachment.ReceivingHeaderBuffer, 0); // You have to make sure payloadLength is > 0 and < than what you think would be too big, // just to keep hackers away which I don't for this simple snippet // but keep in mind that serialized C# Objects are big ... // Now a decision, should I create a new byte[] or just reuse the one used for the previous packet? if (attachment.ReceivingPayloadBuffer == null || // If the payload byte[] is null // or its capacity is less than we need (ulong)attachment.ReceivingPayloadBuffer.Length < attachment.ExpectedReceivingPayloadLength) { // Then create a new one attachment.ReceivingPayloadBuffer = new byte[attachment.ExpectedReceivingPayloadLength]; } // Begin reading the payload now ClientSocket.BeginReceive(attachment.ReceivingPayloadBuffer, 0, (int)attachment.ExpectedReceivingPayloadLength, SocketFlags.None, OnPayloadReceived, attachment); return; } else { // We are not done reading the header, keep reading it // For example if have just read 3 bytes, now we are expecting 5 more bytes (because we know // the header should be 8 bytes long, so we begin reading and filling the buffer from offset 3. // So: NumberOfBytesReadSoFar would be 3, // second parameter would be NumberOfBytesReadSoFar(3), // forth parameter would be 5 (because of: 8 - 3). // Hope make sense, it is easy. ClientSocket.BeginReceive(attachment.ReceivingHeaderBuffer, (int)attachment.NumberOfBytesReadSoFar, (int)((ulong)attachment.ReceivingHeaderBuffer.LongLength - attachment.NumberOfBytesReadSoFar), SocketFlags.None, OnHeaderReceived, attachment); return; } } } catch (Exception exception) { OnDisconnected(exception); } }