/// <summary>
        /// sends acknowledgement of every publish message recieved. If server does not receive ack, then it keeps on sending
        /// publish messages
        /// </summary>
        /// <param name="msg"></param>
        protected void sendAcknowledement(RetryableMessage msg)
        {
            short messageId = msg.getMessageId();

            if (msg.getQos() == QoS.AT_LEAST_ONCE || msg.getQos() == QoS.EXACTLY_ONCE)
            {
                Message puback = new PubAckMessage(messageId, this);
                puback.write();
            }
        }
 protected void handleMessage(PubAckMessage msg)
 {
 }
        /// <summary>
        /// reads message from messagestream buffer. It reads first byte of flags, which is passed further to restore buffer
        /// if buffer does not  contains complete message as of now. An exception is thrown which is ignored by caller
        /// </summary>
        /// <returns></returns>
        public Message readMessage()
        {
            byte        flags  = input.readByte();
            Header      header = new Header(flags);
            Message     msg    = null;
            MessageType type   = header.getType();

            switch (type)
            {
            case MessageType.CONNACK:
                msg = new ConnAckMessage(header, this);
                break;

            case MessageType.PUBLISH:
                msg = new PublishMessage(header, this);
                break;

            case MessageType.PUBACK:
                msg = new PubAckMessage(header, this);
                break;

            case MessageType.PUBREC:
                msg = new PubRecMessage(header, this);
                break;

            case MessageType.PUBREL:
                msg = new PubRelMessage(header, this);
                break;

            case MessageType.SUBACK:
                msg = new SubAckMessage(header, this);
                break;

            case MessageType.SUBSCRIBE:
                msg = new SubscribeMessage(header, this);
                break;

            case MessageType.UNSUBACK:
                msg = new UnsubAckMessage(header, this);
                break;

            case MessageType.PINGRESP:
                msg = new PingRespMessage(header, this);
                break;

            case MessageType.PINGREQ:
                msg = new PingReqMessage(header, this);
                break;

            case MessageType.DISCONNECT:
                msg = new DisconnectMessage(header, this);
                break;

            case MessageType.CONNECT:
                msg = new ConnectMessage(header, this);
                break;

            default:
                throw new NotSupportedException("No support for deserializing " + header.getType() + " messages");
            }
            try
            {
                msg.read(input);
            }
            catch (IndexOutOfRangeException outOfRange)
            {
                throw outOfRange;
            }
            return(msg);
        }