Rogue Wave banner
Previous fileTop of DocumentContentsIndexNext file

17.6 Event-Driven Receptionist

The event-driven receptionist allows you to handle multiple calls at once, without using concurrent processing. It does this by mediating all communication between clients and worker callbacks.

17.6.1 Event-Driven Receptionist Interface

Here's the public interface to the event-driven receptionist.

//1This is a typedef of the callback function signature. The callback function signature is a little different than for the sequential server. In the sequential server case, the callback function was passed back a net library portal object directly to use for communication. Since this receptionist insists on mediating all communication, this won't do here. Also, the event-driven receptionist does not call the worker for each incoming connection, but rather for each chunk of input received from a client.

The callback function receives an integer identifier which uniquely identifies the client sending the input, the input itself, a reference to the receptionist, and its client data. As we'll see, the reference to the receptionist together with the client identifier can be used to tell the receptionist to communicate with the client.
//2The constructor for the event-driven receptionist is exactly like the sequential receptionist constructor.
//3This function is used by the worker to send data to a client. The implementation does not communicate directly with the client (this might block, and a fundamental principal of this receptionist is that workers do not block. Instead, the receptionist maintains a buffer of data waiting to be sent to each client, and send() adds the data to the appropriate buffer.
//4When the worker is ready to hang up, it calls close() on the receptionist. As with send(), the action is not carried out immediately. Instead, this connection is added to the list of connections ready to be closed. The connection will actually be closed only after all pending output has been sent.
//5This call causes the receptionist to handle a single communication call on each portal which is ready. If no new connections have arrived, none of the currently active input lines have available input, and none of the output lines with data pending are ready for writing, then processPacket() blocks until something can be done.

This function is the heart of the event-driven receptionist. It's implementation uses RWSocketAttributes and the net library global function rwSocketSelect() to detect which communication channels are ready.

17.6.2 Event-Driven Greeter Callback

The greeting callback for the event-driven server is more complicated than for the iterative server. The complexity arises because the callback must be able to handle multiple clients at the same time. To do this, the callback maintains a dictionary of input buffers for each connection it is currently handling. If new input arrives and does not contain a newline, then we don't have the complete salutation for this client, so the input is appended to the client's input buffer. If the input does contain a newline, then we send the previous greeting and shut down the connection. Here's the code.

//1This is the mapping from client identifiers to unprocessed input from that client. Without this saving of old input, we could not handle the case of multiple clients, where each salutation was not always delivered in a single packet. The dictionary is declared using static storage so that it persists from one call of the callback to the next.
//2Search the input for either a newline character or a line feed. Although the greeting protocol calls for a newline, we want to make the server more robust by allowing salutations that terminate with a carriage return/ linefeed pair.
//3Test if we are in shape to respond to the client. We are ready to respond if either we found the end of the salutation, or if the input is null. Null input indicates that the client has closed its writing side of the connection.
//4Chop off the rest of the input past the salutation.
//5If there has been previous input queued up for this client, we merge the previous input with the string newGreeting and clean up the buffer.
//6Greet the client. Of course, we don't communicate with the client directly. Instead, go through the receptionist.
//7Close the connection, since we are done. As with sending data to the client, we close the connection indirectly via the receptionist.
//8If we have not yet received the complete greeting, then append this input to an input buffer.

17.6.3 The Event-Driven Greeting Program

The event-driven greeting mainline is nearly identical to the sequential greeting mainline.

//1Construct the address on which to wait for connections. This hardwires the address to TCP port 3010.
//2Build the receptionist object. The callback function is registered at construction time.
//3The application runs in an infinite loop, answering one call after another.
//4Handle a packet.
//5Problems with a single packet are handled by an inner try block and caught here. After an error message is printed, the server goes on and processes other packets. This improves the robustness of the server.


Previous fileTop of DocumentContentsIndexNext file

©Copyright 2000, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.