private void OnHeaderReceived(IAsyncResult result) { ClientConnectionAttachment attachment = (ClientConnectionAttachment)result.AsyncState; // Keep track of how many bytes we have read, notice the + sign attachment.NumberOfBytesReadSoFar += (ulong)attachment.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 attachment.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. attachment.ClientSocket.BeginReceive(attachment.ReceivingHeaderBuffer, (int)attachment.NumberOfBytesReadSoFar, (int)((ulong)attachment.ReceivingHeaderBuffer.LongLength - attachment.NumberOfBytesReadSoFar), SocketFlags.None, OnHeaderReceived, attachment); return; } } }
private void ReadHeader(ClientConnectionAttachment attachment) { // BeginReceive is asynchronous, so this function call returns immediately // First we want the header so begin receiving the header (8 bytes long) attachment.ClientSocket.BeginReceive(attachment.ReceivingHeaderBuffer, 0 /*Offset*/, attachment.ReceivingHeaderBuffer.Length /* 8 bytes long to read for the header */, SocketFlags.None, OnHeaderReceived, attachment); }
public void OnPendingClientConnection(IAsyncResult result) { Console.WriteLine("Connection received"); ClientConnectionAttachment attachment = new ClientConnectionAttachment(); Socket serverSocket = ((Socket)result.AsyncState); attachment.ClientSocket = serverSocket.EndAccept(result); // Schedule one server async Accept AcceptOneClient(serverSocket); // Schedule an async read ReadHeader(attachment); }
private void OnPayloadReceived(IAsyncResult result) { ClientConnectionAttachment attachment = (ClientConnectionAttachment)result.AsyncState; // Keep track of how many bytes we have read, notice the + sign attachment.NumberOfBytesReadSoFar += (ulong)attachment.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 attachment.ClientSocket.BeginReceive(attachment.ReceivingPayloadBuffer, (int)attachment.NumberOfBytesReadSoFar, // Offset (int)((ulong)attachment.ReceivingPayloadBuffer.LongLength - attachment.NumberOfBytesReadSoFar), SocketFlags.None, OnPayloadReceived, attachment); } else { OnPacketReady(attachment); 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(attachment); } } else { // This most likely means socket closed Console.WriteLine("Read 0 bytes"); } }
private void OnPacketReady(ClientConnectionAttachment attachment) { Notification notification = Notification.DeSerialize(attachment.ReceivingPayloadBuffer); Console.WriteLine("Message: {0}\nCreated At {1}", notification.Message, notification.CreatedAt); }