Thursday 7 March 2013

Posted by Prasad KM | 04:11 Categories:

Asynchronous socket data received in c#

 

The receive process, if you're using some socket service header, needs to check the header, and continues to read bytes till all the packet message is received. This process is executed in the read callback:
private void BeginReadCallback(IAsyncResult ar)
{
...

    byte[] received = null
    byte[] rawBuffer = null;
    byte[] connectionHeader = connection.Header;

    readMessage.PacketOffSet += readBytes;

    if ((connectionHeader != null) && (connectionHeader.Length > 0))
    {

        //----- Message with header!
        int headerSize = connectionHeader.Length + 2;

        bool readPacket = false;
        bool readSocket = false;

        do
        {
            connection.LastAction = DateTime.Now;

            if (readMessage.PacketOffSet > headerSize)
            {
                //----- Has Header!
                for (int i = 0; i < connectionHeader.Length; i++)
                {
                    if (connectionHeader[i] != readMessage.PacketBuffer[i])
                    {
                        //----- Bad Header!
                        throw new BadHeaderException(
                          "Message header is different from Host header.");
                    }
                }

                //----- Get Length!
                int messageLength =
                  (readMessage.PacketBuffer[connectionHeader.Length] << 8) +
                  readMessage.PacketBuffer[connectionHeader.Length + 1];

                if (messageLength > FMessageBufferSize)
                {
                    throw new MessageLengthException("Message " +
                      "length is greater than Host maximum message length.");
                }

                //----- Check Length!
                if (messageLength == readMessage.PacketOffSet)
                {
                    //----- Equal -> Get rawBuffer!
                    rawBuffer =
                      readMessage.GetRawBuffer(messageLength, headerSize);

                    readPacket = false;
                    readSocket = false;
                }
                else
                {
                    if (messageLength < readMessage.PacketOffSet)
                    {
                        //----- Less -> Get rawBuffer and fire event!
                        rawBuffer =
                          readMessage.GetRawBuffer(messageLength, headerSize);

                        //----- Decrypt!
                        rawBuffer = CryptUtils.DecryptData(connection,
                                    ref rawBuffer, FMessageBufferSize);

                        readPacket = true;
                        readSocket = false;

                        received = new byte[rawBuffer.Length];
                        Array.Copy(rawBuffer, 0, received, 0, 
                            rawBuffer.Length);
                        FireOnReceived(connection, received, false);
                    }
                    else
                    {
                        if (messageLength > readMessage.PacketOffSet)
                        {
                            //----- Greater -> Read Socket!
                            if (messageLength > readMessage.PacketLength)
                            {
                                readMessage.Resize(messageLength);
                            }

                            readPacket = false;
                            readSocket = true;
                        }
                    }
                }
            }
            else
            {
                if (readMessage.PacketRemaining < headerSize)
                {
                    //----- Adjust room for more!
                    readMessage.Resize(readMessage.PacketLength + headerSize);
                }

                readPacket = false;
                readSocket = true;
            }

        } while (readPacket);

        if (readSocket)
        {
            //----- Read More!
            ...
            .BeginReceive(readMessage.PacketBuffer, readMessage.PacketOffSet,
                          readMessage.PacketRemaining, SocketFlags.None, ...);
            ...
        }
    }
    else
    {
        //----- Message with no header!
        rawBuffer = readMessage.GetRawBuffer(readBytes, 0);
    }

    if (rawBuffer != null)
    {
        //----- Decrypt!
        rawBuffer = CryptUtils.DecryptData(connection,
                    ref rawBuffer, FMessageBufferSize);

        received = new byte[rawBuffer.Length];
        Array.Copy(rawBuffer, 0, received, 0, rawBuffer.Length);
        FireOnReceived(connection, received, true);

        readMessage.Resize(FSocketBufferSize);
...
The read callback method first checks if the connection has some header and, if not, just gets the raw buffer and continues. If the connection has some header, the method needs to check the message header against the socket service header. Before doing that, it checks if the packet message length is greater than the connection header length, to ensure that it can parse the total message length. If not, it reads some bytes. After checking the header, the method parses the message length, and checks with the packet length. If the length is equal, it gets the raw buffer and terminates the loop. If the message length is less than that of the packet message, we have the message plus some data. So, the method gets the raw buffer and continues to read using the same MessageBuffer class. If the length of the message is greater than that of the packet message, before reading some data, it just resizes the packet buffer to the message size, ensuring enough room for more read bytes.

0 comments:

  • RSS
  • Delicious
  • Digg
  • Facebook
  • Twitter
  • Linkedin
  • Youtube