Polling Concepts
The initial time service is akin to a restaurant with one table and one waiter: It can only service one client at a time. Everyone else waits outside until the current client has finished their business. Chances are, you do not require (nor want) the waiter at the table for the entire meal; instead, he can periodically check in on you and divide the rest of his time among several other tables.
This recurring check for activity is called "polling," and for socket programming it offers a cheap form of multitasking. A program can keep track of client sockets and cycle through those that need attention. Under UNIX-like operating systems, the poll() and select() functions determine which sockets in a given set have waiting data.
The Reactor pattern formalizes polling's event-driven model into a framework. Its unit of currency is the handle, which is something that can receive events. Here, a handle is a socket (or a variable related to a socket), and events indicate that data is waiting; that is, attempts to accept a client or read data will not block.
Each handle has an associated handler that processes events. For example, a Reactor implementation of the time service would have handlers to process the commands sent by the remote clients.
The central Reactor object ties all of this together. Code registers handles with the Reactor, which runs a loop that checks for events on those handles. For each handle that has a waiting event, the Reactor calls its associated handler.
How the Reactor determines whether there are waiting events depends on the implementation. The textbook Reactor description calls this piece a "synchronous event dispatcher." That's a five-dollar word for calls such as select() or poll().
The basic Reactor isn't as responsive as a multithreaded service; on each iteration of its event loop, it processes waiting events in serial fashion. That means a couple of slow connections at the head of the line can delay service to other connections in the set. Nonetheless, it's cheap to set up and will likely suffice for a small and/or low-activity client base. (For a more high-powered solution, consider the Proactor pattern described in POSA2.)