4.20. CharInBuffer CLASS

Class CharInBuffer is similar to class xdrIOBuffer. CharInBuffer is a bucket for the character-based message-oriented communication protocols. It helps in reading, parsing, and storing record-oriented messages from Socket asynchronously. The record terminator (or delimiter) can be multibyte. In record-oriented message protocols, each message is terminated with predefined sequence of control characters (or one control character).

CharInBuffer reads characters from the socket stream, scanning for the termination character. When terminator is detected, the block of characters collected in the bucket so far becomes ready for further processing by the application. The processed termination character is always removed from the bucket.

If either Socket::read() error is encountered, or an overflow occurs (number of characters that have been read exceeds the maximum limit), the object goes into the error state and won't accept further input, unless reset.

4.20.1. DESCRIPTION


class CharInBuffer
{
public:
    enum state_t {start, waiting, complete, error}

	CharInBuffer (size_t size_, const string& delimiter_ = "");

	operator void* () const;
	const char* c_str () const;
	size_t length () const;
	size_t size () const; 

	void reset ();
	void dump () const;

	state_t state () const;

	friend ASSA::Socket& operator>>(ASSA::Socket&, ASSA::CharInBuffer&);
};
	  

4.20.2. USAGE

Constructor accepts an expected bucket size and termination character(s):


class Message : public EventHandler
{
public:
    Message () 
        : m_msg (10, "\n") // expect up to 10 characters; terminate with NL
    {
        /// ...
    }

    int handle_read (int fd_);

private:
    void process_msg ();

    CharInBuffer m_msg;
};

	  

Note

If you don't specify delimiter character(s) in the constructor, CharInBuffer accumulates up to size_ characters and then goes to "complete" state. It won't read any more characters from the Socket, until you call reset() to clear the bucket.

When data arrives on a socket, we gradually read the message and collect it in the bucket until we encounter the termination character.

int 
Message::handle_read (fd_)
{
    Socket& s = *this;
    s >> m_msg;          // Read data from the socket

    if (m_msg)           // If we encountered the terminator
    {
         process_msg ()  // Process received message further ...
         m_msg.reset (); // Prepare for the next message
    }
    else {     
        if (m_msg.state () == ASSA::CharInBuffer::error) 
        {
            return -1;   // Buffer overflow - drop connection
        }
    }

    return s.eof () ? -1 : s.in_avail (); // wait for complete message
}
 
	  

You can access the received bytes with c_str() member function that returns a pointer to the beginning of the buffer.


void
Message::process_msg ()
{
    if (expected_msg == m_msg.c_str ()) {
        ...
    }
}