• No results found

The Initial Logging Server

In document C++ Network Programming Vol 1 (Page 95-100)

Implementing the Networked Logging Service

4.4 The Initial Logging Server

return

We'll use these two insertion and extraction operators to simplify our net-worked logging application shortly.

4.4 The Initial Logging Server

Our first networked logging service implementation defines the initial de-sign and the core reusable class implementations. The logging server lis-tens on a TCP port number defined in the operating system's network ser-vices file as ace_logger, which is a practice used by many networked servers. For example, the following line might exist in the UNIX

services file:

ace_logger # Connection-oriented Logging Service

Client applications can optionally specify the TCP port and the IP ad-dress where the client application and logging server should rendezvous to exchange log records. If this information is not specified, however, the port number is located in the services database, and the host name is assumed to be the ACE_DEFAULT_SERVER_HOST, which is defined as on most OS platforms. Once it's connected, the client sends log records to the logging server, which writes each record to a file. This section presents a

4.4 The Initial Logging Server 81

Figure 4.4: Logging Server Example Classes

set of reusable classes that handle passive connection establishment and data transfer for all the logging servers shown in this book.

The Logging Server Base Class Now that previous sections described

CDR, and we'll use these classes in a new base class that will simplify our logging server implementations throughout the book. Fig-ure 4.4 illustrates our Logging_Server abstract base class, the

Handler class we'll develop in Section 4.4.2, and the concrete logging server classes that we'll develop in future chapters. We put the defini-tion of the Logging_Server base class into the following header file called

82 CHAPTER 4 Implementing the Networked Logging Service

ttinclude

// Forward declaration.

class

class Logging Server {

// Template Method that runs logging server's event loop.

virtual int run (int argc, char

// The following four methods are that can be // overridden by subclasses.

virtual int open port =

virtual int wait_for_multiple_events () { return } virtual int handle_connections () = 0;

virtual int handle_data * = 0) = 0;

// This helper method can be used by the hook

int &, * =

// Close the socket endpoint and shutdown ACE.

virtual ~Logging_Server 0 {

// Accessor.

&acceptor return

// Socket acceptor ACE_SOCK_Acceptor

All the subsequent networked logging service examples will include this header file, subclass Logging_Server, and override and reuse its each of which we describe below. The implementation file Logging_

cpp includes the following ACE header flies:

#include ttinclude ttinclude

Section The Logging Server 83

The Logging Template Method

This public method performs the canonical initialization and event loop steps used by most of the logging servers in this book.

int (int argc, char

{

if (open (argc > 1 ? atoi : 0) == -1) return

for {

if (wait_for_multiple_events () == -1) return -1;

if (handle_connections () == -1) return -1;

if (handle data () == -1) return -1;

} return }

The code above is an example of the Template Method pattern

which the skeleton of an algorithm in an operation, deferring some steps to hook methods that can be overridden by subclasses. The calls to open , wait_f , handle_data , and handle_

connections in the template method are all hook methods that can be overridden by subclasses.

The Logging-Server Hook Methods

Each hook method in the Logging_Server class has a role and a default behavior that's described briefly below.

Logging This method initializes the server address and the acceptor endpoint to listen passively on a desig-nated port number. Although it can be overridden by subclasses, the default implementation shown below suffices for all the examples in this book:

int logger_port)

{

// Raises the number of available socket handles to // the maximum supported by the OS platform.

ACE_INET_Addr int result;

84 CHAPTER 4 Implementing the Networked Logging Service

// Start listening and enable reuse of listen address // for quick

return (server_addr,

}

Although an constructor accepts the port number and host name as arguments, we avoid it here for the following reasons:

1. We allow the user to either pass a port number or use the default service name, which requires different calls

2. Networking addressing functions such as may be called, which can surprise programmers who don't expect a construc-tor to delay its execution until the server host address is resolved and 3. We need to issue the proper diagnostic if there was an error.

Section on page 256 explains why ACE doesn't use native C++ excep-tions to propagate errors.

Note the second argument on the call. It causes the socket option to be set on the acceptor socket, allowing the program to restart soon after it has been stopped. This avoids any clashes with sockets in state left from the previous run that would otherwise prevent a new logging server from listening for logging clients for several minutes.

The role of this method is to wait for multiple events to occur. It's default implementation is a no-op;

that is, it simply returns 0. This default behavior is overridden by imple-mentations of the logging server that use the select -based synchronous event demultiplexing mechanisms described in Chapter 7.

Logging The role of this hook method is

to accept one or more connections from clients. We it as a pure virtual method to ensure that subclasses implement it.

The role of this hook method is to receive a log record from a client and write it to a log file. We also define it as a pure virtual method to ensure that subclasses implement it.

Section The Initial Logging Server 85

In document C++ Network Programming Vol 1 (Page 95-100)