Chapter 5. The ACE Service Configurator Framework

更新时间:2023-07-20 23:28:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

Ru-Brd

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

Service Configurator framework uses to

configure and control a service

implementation. Control operations

include initializing, suspending,

resuming, and terminating a service.

ACE_Service_Repository A central repository for all services

managed using the ACE Service

Configurator framework. It provides

methods for locating, reporting on, and

controlling all of an application's

configured services.

ACE_Service_Repository_Iterator A portable mechanism for iterating

through all the services in a repository.

ACE_Service_Config Provides an interpreter that parses and

executes scripts specifying which

services to (re)configure into an

application (e.g., by linking and

unlinking DLLs) and which services to

suspend and resume.

The most important relationships between the classes in the ACE Service

Configurator framework are shown in . These classes play the following roles in accordance with the Component Configurator pattern []:

Figure 5.1. The ACE Service Configurator Framework Classes

lConfiguration management layer classes perform application-independent strategies to install, initialize, control, and shut down service objects. The classes in the configuration management layer in the ACE

Service Configurator framework include ACE_Service_Config,

ACE_Service_Repository, and ACE_Service_Repository_Iterator. Application layer classes implement concrete services to perform an application's processing. In the ACE Service Configurator framework,

application layer classes are descendants of ACE_Service_Object, which

in turn inherits from ACE_Event_Handler (), thereby enabling

service objects to be linked and unlinked dynamically, and to participate in

the ACE Reactor framework. l

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

The ACE Service Configurator framework provides the following benefits:

lFlexibility. The framework allows developers to offer multiple services, and a choice of different implementations of services, that can be assembled at run time. The choices concerning which services to execute on which

network node(s) can be made (and changed) at any point, ranging from

application build time to the actual point when services start running.

Developers can also limit choices (e.g., by not offering dynamically linkable services) where desired.

Configurability. Developers can customize and configure application data for nearly any aspect of a service and for each deployment. Services can be developed to read traditional configuration data, such as port numbers,

network addresses, and file system locations. Moreover, services can allow

tuning and performance decisions to be deferred until the right information

is available to guide them. For example, depending on the run-time

platform's available multithreading facilities and available CPUs, it may be

either more or less efficient to run multiple services in separate threads or

separate processes. The ACE Service Configurator framework enables

applications to be configured by site-knowledgable administrators, or they

can select and tune these behaviors flexibly at run time, when there's

enough information to help match client demands with available system

processing resources.

Managability. All configuration information can be stored in a configuration script file, known as svc.conf. The framework uses these scripts to load

and configure services. An application's installation procedure can record

settings in an svc.conf file. Administrators can also edit and tune this

information as needed, without rebuilding the application itself. Applications can form their own configuration directives and pass them directly to the

ACE Service Configurator framework. The framework groups an application's services into one administrative unit and enables an application to report on its services and their states.

Consistency. The framework imposes a uniform interface for initializing, suspending, resuming, and terminating a service. This uniformity provides

consistency to framework users and allows services to be treated as building blocks that can be assembled flexibly to form complete applications.

Maintainability. The framework's decoupling of service implementation from configuration into networked applications allows service

implementations to evolve over time, independently of which networked

applications they're included in. Each service can be developed and tested

independently, which simplifies subsequent service composition and

increases reuse.

Enhanced dynamism and control. The framework enables a service to be reconfigured dynamically without modifying, recompiling, or statically relinking existing code. Each service can also be reconfigured without lllll

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

affecting other services or stopping and restarting the server process itself.

These reconfiguration capabilities are often required for high-availability

applications, such as mission-critical systems that perform online transaction processing or telecom call processing.

The remainder of this chapter motivates and describes the capabilities of each class in the ACE Service Configurator framework. We also illustrate how this framework can be used to enhance the extensibility of our networked logging server. If you aren't familiar with the Component Configurator pattern from

POSA2 we recommend that you read about it first before delving into the detailed examples in this chapter.

Ru-Brd

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

are good candidates to incorporate into a framework. Enforcing a uniform interface across all networked services makes it easier to configure and manage them consistently. In turn, this consistency simplifies application development and

deployment by mitigating key challenges inherent in creating reusable administrativeconfiguration tools. To provide a uniform interface between the ACE Service

Configurator framework and the application-defined services, each service must be adescendant of a common base class called ACE_Service_Object.

Class Capabilities

ACE_Service_Object provides a uniform interface that allows service

implementations to be configured and managed by the ACE Service Configurator framework. This class provides the following capabilities:

lIt provides hook methods that initialize a service (e.g., allocating its resources)and shut a service down (e.g., cleaning up its resources).

It provides hook methods to suspend service execution temporarily and to resume execution of a suspended service.

It provides a hook method that reports key service information, such as its purpose, current status, and the port number where it listens for client

connections. ll

These methods are generally invoked as callbacks from the ACE Service Configuratorframework when it interprets the configuration directives described on page 141. The interface for ACE_Service_Object is shown in (page 120). By inheriting from ACE_Event_Handler and ACE_Shared_Object, subclasses of ACE_Service_Object can be dispatched by the ACE Reactor framework and can belinked and unlinked from a DLL dynamically, respectively. The key configuration-related hook methods of ACE_Service_Object are outlined in the following table:

Figure 5.2. The ACE_Service_Object Class

Method Description

init() Used by the framework to instruct a service to initialize itself.

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

"argc/argv"-style arguments can be passed to init() to control service

initialization.

fini() Used by the framework to instruct a service to shut itself down. This

method typically performs termination operations that release a service's

resources, such as memory, synchronization locks, or I/O handles.

suspendUsed by the framework to instruct a service to suspend and resume () execution.

resume

()

info() Used to query a service for certain information about itself, such as its

name, purpose, and network address. Clients can query a server to retriev

this information and use it to contact a particular service running in a

server.

These hook methods collectively impose a uniform interface between the ACE ServiceConfigurator framework and the application-defined services that it manages.

Application services that inherit from ACE_Service_Object can selectively overrideits hook methods, which are called back at the appropriate time by the ACE Service Configurator framework in response to specific events. For example, a service objectinit() hook method is called when the Service Configurator framework executes a directive to activate the service (both the dynamic and static directives activate aservice, as shown on page 141). The init() hook method must return 0 if initialization succeeds and -1 if it fails. If (and only if) init() succeeds, the

corresponding fini() method will be called on the service object when the ACE Service Configurator framework executes the remove directive for the service, or shuts down all services.

The Service Configurator is the first ACE framework we've studied that has extensiveinteraction with administrators or applications. These interactions introduce the needto operate with local character sets. shows the ACE_TCHAR type, which helps ACE deal with non-ASCII character sets portably. ACE's facilities for handling wide-character and Unicode characters are described in . We'll use this facility to handle character strings in the remainder of this book.

Example

To illustrate the ACE_Service_Object class, we reimplement our reactive logging server from the Example portion of . This revision can be configured dynamically by the ACE Service Configurator framework, rather than configured statically into the main() program shown on page 84. To accomplish this, we'll applthe Adapter pat-tern [] to create the following template class in the

Reactor_Logging_Server_Adapter.h header file:

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

sets in use today require more than one byte, or octet, to represent each

character. Characters that require more than one octet are referred to as

"wide characters." The most popular multiple octet standard is ISO/IEC

10646, the Universal Multiple-Octet Coded Character Set (UCS). Unicode is a separate standard, but is essentially a restricted subset of UCS that uses two octets for each character (UCS-2). Many Windows programmers are familiar with Unicode.

C++ represents wide characters with the wchar_t type, which enables

methods to offer multiple signatures that are differentiated by their character type. Wide characters have a separate set of C string manipulation functions, however, and existing C++ code, such as string literals, requires change for wide-character usage. As a result, programming applications to use wide-

character strings can become expensive, especially when applications written initially for U.S. markets must be internationalized for other countries. To

improve portability and ease of use, ACE uses C++ method overloading and the macros described below to use different character types without

changing APIs:

Macro Usage

Configuration setting to build

ACE with its wide-character

methods

Configuration setting that directs

ACE to use wide characters

internally

Defined as either char or

wchar_t, to match ACE's

internal character width

Defines the string literal str

correctly based on ACE_USES_WCHAR

Converts a char * string to

ACE_TCHAR format, if needed

Converts an ACE_TCHAR string to char * format, if needed ACE_HAS_WCHAR ACE_USES_WCHAR ACE_TCHAR ACE_TEXT(str) ACE_TEXT_CHAR_TO_TCHAR(str) (str) ACE_TEXT_ALWAYS_CHAR

ACE must be built with the ACE_HAS_WCHAR configuration setting for

applications to use wide characters. Moreover, ACE must be built with the ACE_USES_WCHAR setting if ACE should also use wide characters

internally. The ACE_TCHAR and ACE_TEXT macros are illustrated in examples throughout this book.

ACE also supplies two string classes, ACE_CString and ACE_WString,

which hold narrow and wide characters, respectively. These classes are

analogous to the standard C++ string class, but can be configured to use custom memory allocators and are more portable. ACE_TString is a

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

template <class ACCEPTOR>

class Reactor_Logging_Server_Adapter : public ACE_Service_Object {public:

// Hook methods inherited from <ACE_Service_Object>.

virtual int init (int argc, ACE_TCHAR *argv[]);

virtual int fini ();

virtual int info (ACE_TCHAR **, size_t) const;

virtual int suspend ();

virtual int resume ();

private:

Reactor_Logging_Server<ACCEPTOR> *server_;

};

This template inherits from the ACE_Service_Object class and contains a pointer a Reactor_Logging_Server object (page 83). We instantiated this template with the ACCEPTOR class parameter to defer our choice of the acceptor factory until later the design cycle. The Adapter pattern is a good choice here because it allows reuse oour existing Reactor_Logging_Server class. If we were designing this example from scratch with the ability to be configured as a service, however, a more direct approach would be to derive Reactor_Logging_Server from

ACE_Service_Object instead of from ACE_Event_Handler. In that case, the adapter class would not be needed, and we could still defer the choice of the acceptofactory until later. illustrates the lifecycle of the objects in this example when an instance of Reactor_Logging_Server_Adapter is configured dynamically. When this service configured into the address space of an application, the ACE Service Configurator framework creates an instance of Reactor_Logging_Server_Adapter and invokethe following init() hook method automatically:

Figure 5.3. Life Cycle of the Dynamic Reactor Logging Server

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

1 template <class ACCEPTOR> int

2 Reactor_Logging_Server_Adapter<ACCEPTOR>::init

3 (int argc, ACE_TCHAR *argv[])

4 {

5 int i;

6 char **array = 0;

7 ACE_NEW_RETURN (array, char*[argc], -1);

8 ACE_Auto_Array_Ptr<char *> char_argv (array);

9

10 for (i = 0; i < argc; ++i)

11 char_argv[i] = ACE::strnew (ACE_TEXT_ALWAYS_CHAR(argv[i]));12 ACE_NEW_NORETURN (server_, Reactor_Logging_Server<ACCEPTOR> 13 (i, char_argv.get (),

14 ACE_Reactor::instance ())); 15 for (i = 0; i < argc; ++i) ACE::strdelete (char_argv[i]); 16 return server_ == 0 ? -1 : 0;

17 }

Lines 5?1 The ACE Service Configurator framework passes argv as an array of ACE_TCHAR pointers, but the Reactor_Logging_Server constructor accepts a cha* array. The init() method therefore uses the ACE_TEXT_ALWAYS_CHAR macto convert to the char format where needed. This macro creates a temporary objectwith the transformed string, which is then copied via ACE::strnew() to preserve itthrough the Reactor_Logging_Server constructor. Sidebar 29 (page 125) describthe ACE::strnew() and ACE::strdelete() methods.

Lines 12?4 Dynamically allocate an instance of the Reactor_Logging_Server thacontains the desired reactor, acceptor, and handlers.

Line 15 Free the memory used for the converted argv strings.

When instructed to remove the dynamically configured logging service, the ACE Service Configurator framework invokes the

Reactor_Logging_Server_Adapter::fini()

hook method shown below:

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

template <class ACCEPTOR> int

Reactor_Logging_Server_Adapter<ACCEPTOR>::fini ()

{ server_->handle_close (); server_ = 0; return 0; }

This method calls Reactor_Logging_Server::handle_close(), which deletes thReactor_Logging_Server object allocated by init(). The ACE Service

Configurator framework uses the "gobbler" function (page 137) to delete a service object after calling its fini() hook method. We therefore must not call delete thiin fini().

The info() hook method reports service-specific information when the framework requests it. Our info() method formats a string containing the TCP port it's listeninon:

1 template <class ACCEPTOR> int

2 Reactor_Logging_Server_Adapter<ACCEPTOR>::info

3 (ACE_TCHAR **bufferp, size_t length) const {

4 ACE_TYPENAME ACCEPTOR::PEER_ADDR local_addr;

5 server_->acceptor ().get_local_addr (local_addr);

6

7 ACE_TCHAR buf[BUFSIZ];

8 ACE_OS::sprintf (buf,

9 ACE_TEXT ("%hu"),

10 local_addr.get_port_number ());

11 ACE_OS_String::strcat

12 (buf, ACE_TEXT ("/tcp # Reactive logging server\n")); 13 if (*bufferp == 0) *bufferp = ACE::strnew (buf);

14 else ACE_OS_String::strncpy (*bufferp, buf, length); 15 return ACE_OS_String::strlen (*bufferp);

16 }

Lines 4? Obtain the network address from the instance of ACE_SOCK_Acceptor that's used by the Reactor_Logging_Server.

Lines 7?2 Format a message that explains what the service does and how to contacit.

Line 13 If the caller didn't supply a buffer to hold the formatted message, allocate abuffer and copy the message into it using ACE::strnew(). In this case, the caller must use ACE::strdelete() to free the buffer. ACE does not specify how an implementation of info() must allocate memory. Developers writing an

implementation of info() must therefore define and clearly document the policy fortheir implementations. It's strongly recommended that developers use ACE::strnew

() to allocate the string, and require their users to call ACE::strdelete() to free the memory. describes the motivation for these methods.

Line 14 If the caller did supply a buffer for the message, copy the formatted messaginto it, limited to the length passed by the caller.

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

页码,11/40

Line 15 Return the length of the message. Sidebar 29: Portable Heap Operations with ACE

Library functions and classes, such as

Reactor_Logging_Server_Adapter::info() (page 124), often allocate memory dynamically. Memory allocated dynamically in C++ programs should eventually be freed. To write portable C++ programs, it's important to match these allocate and free operations to avoid corrupting the heap (also known as the freestore).

A surprisingly common misconception is that simply ensuring the proper

matching of calls to operator new() and operator delete() (or calls to malloc() and free()) is sufficient for correct heap management. This

strategy relies on the implicit assumption that there's one universal heap per process. In practice, however, a heap is simply a memory area managed by some run-time component, such as the C or C++ run-time library. If an

executing program is exposed to multiple run-time library instances, it's likely there will be multiple heaps as well.

For example, Windows supplies multiple variants of the C/C++ run-time

library, such as Debug versus Release and Multithreaded versus Single-threaded. Each of these variants maintains its own heap. Memory allocated from one heap must be released back to the same heap. Thus, correct heap management requires not only matching the proper method/function calls,

but also making them through the same run-time library. It's easy to violate these requirements when code from one subsystem or provider frees

memory allocated by another.

To assist in managing dynamic memory portably, ACE offers matching

allocate and free methods listed in the table below:

Method

ACE::strnew() Usage Allocates memory for a copy of a

character string and copies the string

into it.

Releases memory allocated by strnew

().

Allocates a memory block of specified

size.

Allocates a memory block to hold a

specified number of objects, each of a

given size. The memory contents are

explicitly initialized to 0. ACE::strdelete() ACE_OS_Memory::malloc() ACE_OS_Memory::calloc()

ACE_OS_Memory::reallocChanges the size of a memory block () allocated via

ACE_OS_Memory::malloc().

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

Unlike the other ACE_Service_Object hook methods shown in (page 120), an info() method isn't always invoked by the ACE Service Configurator

framework, though it can be. Instead, it's often called directly by a server program, shown in the Service_Reporter::handle_input() method (page 133). Moreoveapplication developers can determine the most useful content of the message since info() doesn't mandate a particular format.

The suspend() and resume() hook methods are similar to each other:

template <class ACCEPTOR> int

Reactor_Logging_Server_Adapter<ACCEPTOR>::suspend ()

{ return server_->reactor ()->suspend_handler (server_); }

template <class ACCEPTOR> int

Reactor_Logging_Server_Adapter<ACCEPTOR>::resume ()

{ return server_->reactor ()->resume_handler (server_); }

Since the Reactor_Logging_Server class descends from ACE_Event_Handler, tserver_ object can be passed to the singleton reactor's suspend_handler() and resume_handler() methods (page 73). Both methods double-dispatch to Reactor_Logging_Server::get_handle() to extract the underlying passive-mosocket handle. This socket handle is then temporarily removed from or replaced in thlist of socket handles handled by the singleton reactor. The Example portion of shows how the Reactor_Logging_Server_Adapter can be configured into anout of a generic server application dynamically.

Ru-Brd

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

页码,13/40

provided by ACE_Service_Object effectively, it must store service information in awell-known repository and be able to access and control these service objects individually or collectively.

Application services in multiservice servers also may require access to each other. Toavoid tightly coupling these services, and to preserve the benefits of delayed configuration decisions, services should be able to locate each other at run time. Therefore, to satisfy the needs of the framework and applications without requiring developers to provide these capabilities in an ad hoc way, the ACE Service

Configurator framework provides the ACE_Service_Repository and

ACE_Service_Repository_Iterator classes.

Class Capabilities

ACE_Service_Repository implements the Manager pattern [Som98] to control thlife cycle of, and the access to, service objects configured by the ACE Service Configurator framework. This class provides the following capabilities:

lIt keeps track of all service implementations that are configured into an application and maintains each service's status, such as whether it's active or suspended.

It provides the mechanism by which the ACE Service Configurator framework inserts, manages, and removes services.

It provides a convenient mechanism to terminate all services, in reverse order otheir initialization.

It allows an individual service to be located by its name. lll

The interface for ACE_Service_Repository is shown in Figure 5.4 (page 128) andits key methods are outlined in the following table:

Figure 5.4. The ACE_Service_Repository Class

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

Method Description ACE_Service_Repository() Initialize the repository and allocate its dynamic open() resources.

ACE_Service_Repository()

close()

The ACE_Service_Repository binds the following entities together:

l

The name of a service, which is represented as a character string, and

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

lAn instance of ACE_Service_Type, which is the class used by the ACE ServiceConfigurator framework to link, initialize, suspend, resume, remove, and unlinkservices from a server statically or dynamically.

The ACE_Service_Type class provides the framework with the operations necessarto act on the configured services. The ACE Service Configurator framework can be used to configure dynamic and static services, as well as the ACE_Module and ACE_Stream capabilities covered in Sections 9.2 and 9.3, respectively.

The ACE_Service_Type class uses the Bridge pattern to allow type-specific data anbehavior in service types to evolve without impacting the class. The

ACE_Service_Type class plays the Abstraction role in this pattern and the ACE_Service_Type_Impl class plays the Implementor role. The following classes each play the ConcreteImplementor role, representing the types of services that canbe recorded in the service repository:

1.ACE_Service_Object_Type桾he object() method returns a pointer to the

associated ACE_Service_Object described in .

2.ACE_Module_Type桾he object() method returns a pointer to the associated

ACE_Module described in Section 9.2.

3.ACE_Stream_Type桾he object() method returns a pointer to the associated

ACE_Stream described in Section 9.3.

For dynamically linked service objects, ACE_Service_Type also stores the handle othe DLL that contains the service's executable code. The ACE Service Configurator framework uses this handle to unlink and unload a service object from a running server when the service it offers is no longer needed. (page 131) shows how a program can use ACE_Dynamic_Service and ACE_Service_Type to retrievservices from ACE_Service_Repository programmatically.

ACE_Service_Repository_Iterator implements the Iterator pattern [GoF] to provide applications with a way to sequentially access the ACE_Service_Type itemin an ACE_Service_Repository without exposing its internal representation. The interface for ACE_Service_Repository_Iterator is shown in Figure 5.5 (page 130) and its key methods are outlined in the following table:

Figure 5.5. The ACE_Service_Repository_Iterator Class

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

Method Description

ACE_Service_Repository_IteratorInitialize the iterator.

()

next() Pass back a pointer to the next

ACE_Service_Type in the repository.

done() Returns 1 when all items have been seen.advance() Move ahead one item in the repository. Never delete entries from an ACE_Service_Repository that's being iterated over since the ACE_Service_Repository_Iterator is not a robust iterator []. Example

This example illustrates how the ACE_Service_Repository and

ACE_Service_Repository_Iterator classes can be used to implement a Service_Reporter class. This class provides a "meta-service" that clients can use obtain information on all services that the ACE Service Configurator framework has configured into an application statically or dynamically. A client interacts with a Service_Reporter as follows:

l

l

lThe client establishes a TCP connection to the Service_Reporter object. The Service_Reporter returns a list of all the server's services to the client.The Service_Reporter closes the TCP/IP connection. (page 132) describes ACE_Service_Manager, which is a class bundled with the ACE toolkit that provides a superset of Service_Reporter features. The Service_Reporter class is described below. We first create a file called Service_Reporter.h that contains the following class definition:

class Service_Reporter : public ACE_Service_Object {

public:

Service_Reporter (ACE_Reactor *r = ACE_Reactor::instance ()) : ACE_Service_Object (r) {}

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

// Hook methods inherited from <ACE_Service_Object>.

virtual int init (int argc, ACE_TCHAR *argv[]);

virtual int fini ();

virtual int info (ACE_TCHAR **, size_t) const;

virtual int suspend ();

virtual int resume ();

protected:

// Reactor hook methods.

virtual int handle_input (ACE_HANDLE);

virtual ACE_HANDLE get_handle () const

{ return acceptor_.get_handle (); }

private:

ACE_SOCK_Acceptor acceptor_; // Acceptor instance.

enum { DEFAULT_PORT = 9411 };

};

Since Service_Reporter inherits from ACE_Service_Object, it can be configureby the ACE Service Configurator framework. The ACE Service Configurator frameworwill create an instance of this class at run time, so the constructor must be public. Sidebar 30: The ACE_Dynamic_Service Template

The ACE_Dynamic_Service class template provides a type-safe way to access the ACE_Service_Repository programmatically. An application process can use this template to retrieve services registered with its local

ACE_Service_Repository. As shown below, the TYPE template parameter ensures that a pointer to the appropriate type of service is returned from the static instance() method:

template <class TYPE>

class ACE_Dynamic_Service {

public:

// Use <name> to search the <ACE_Service_Repository>.

static TYPE *instance (const ACE_TCHAR *name) {

const ACE_Service_Type *svc_rec;

if (ACE_Service_Repository::instance ()->find

(name, &svc_rec) == -1) return 0;

const ACE_Service_Type_Impl *type = svc_rec->type (); if (type == 0) return 0;

ACE_Service_Object *obj =

ACE_static_cast (ACE_Service_Object *, type->object ()); return ACE_dynamic_cast (TYPE *, obj);

}

};

If an instance of the Server_Logging_Daemon service has been linked dynamically and initialized by the ACE Service Configurator framework, an

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

页码,18/40application can use the ACE_Dynamic_Service template to access the service programmatically as shown below:

typedef Reactor_Logging_Server_Adapter<Logging_Acceptor> Server_Logging_Daemon; Server_Logging_Daemon *logging_server= ACE_Dynamic_Service<Server_Logging_Daemon>::instance (ACE_TEXT ("Server_Logging_Daemon")); ACE_TCHAR *service_info= 0; logging_server->info (&service_info); ACE_DEBUG ((LM_DEBUG,"%s\n", service_info)); ACE::strdelete (service_info);Note that this example assumes info() allocates string memory via the ACE::strnew() method discussed in Sidebar 29 (page 125).

Sidebar 31: The ACE_Service_Manager ClassACE_Service_Manager provides clients with access to administrativecommands to access and manage the services currently offered by a network server. These commands"externalize" certain internal attributes of the services configured into a server. During server configuration, an ACE_Service_Manager is typically registered at a well-known communication port, for example, port 9411. Clients can connect to an ACE_Service_Manager at that port and issue one of the following commands.l

help? a list of all services configured into an application via the ACEService Configurator framework is returned to the client.

l

reconfigure? a reconfiguration is triggered to reread the local serviceconfiguration file.

If a client sends anything other than these two commands, its input is passed to ACE_Service_Config::process_directive() (page 141), which enables remote configuration of servers via command-line instructions such as

% echo"suspend My_Service"| telnet hostname 9411It's therefore important to use the ACE_Service_Manager only if your application runs in a trusted environment since a malicious attacker can use it to deny access to legitimate services or configure rogue services in a Trojan Horse manner. For this reason, ACE_Service_Manager is a static service that ACE disables by default. An application can direct ACE to load its static services, including the

file://C:\Documents and Settings\Hank Lee\Local Settings\Temp\~hh79... PDF文件使用"pdfFactory"试用版本创建ÿÿ

2008-4-28

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

The implementations of the Service_Reporter hook methods are placed into the Service_Reporter.cpp file. The ACE Service Configurator framework calls the following Service_Reporter::init() hook method when a Service_Reporterconfigured into an application:

1 int Service_Reporter::init (int argc, ACE_TCHAR *argv[]) { 2 ACE_INET_Addr local_addr (Service_Reporter::DEFAULT_PORT); 3 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:"), 0); 4 get_opt.long_option (ACE_TEXT ("port"),

5 'p', ACE_Get_Opt::ARG_REQUIRED); 6 for (int c; (c = get_opt ()) != -1;)

7 if (c == 'p') local_addr.set_port_number

8 (ACE_OS::atoi (get_opt.opt_arg ())); 9 acceptor_.open (local_addr);

10 return reactor ()->register_handler

11 (this,

12 ACE_Event_Handler::ACCEPT_MASK);

13 }

Line 2 Initialize local_addr to the Service_Reporter's default TCP port numbeLines 3? Parse the service configuration options using the ACE_Get_Opt class described in Sidebar 8 (page 47). We start parsing at argv[0] rather than argv[1]which is the default. If the -p, or the long version --port, option is passed into ini

(), the local_addr port number is reset to that value. Since ACE_Get_Opt alwaysreturns the corresponding short option for any long options it encounters, it's sufficieto test only for 'p' in the loop iterator.

Lines 9?2 Initialize the ACE_SOCK_Acceptor to listen on the local_addr port number and register the instance of Service_Reporter with the reactor for ACCEPT events. When a connection request arrives from a client, the reactor dispatches the following Service_Reporter::handle_input() hook method: 1 int Service_Reporter::handle_input (ACE_HANDLE) {

2 ACE_SOCK_Stream peer_stream;

3 acceptor_.accept (peer_stream);

4

5 ACE_Service_Repository_Iterator iterator

6 (*ACE_Service_Repository::instance (), 0);

7

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

8 for (const ACE_Service_Type *st;

9 iterator.next (st) != 0;

10 iterator.advance ()) {

11 iovec iov[3];

12 iov[0].iov_base = ACE_const_cast (char *, st->name ()); 13 iov[0].iov_len =

14 ACE_OS_String::strlen (st->name ()) * sizeof (ACE_TCHAR);15 const ACE_TCHAR *state = st->active () ?

16 ACE_TEXT (" (active) ") : ACE_TEXT (" (paused) "); 17 iov[1].iov_base = ACE_const_cast (char *, state);

18 iov[1].iov_len =

19 ACE_OS_String::strlen (state) * sizeof (ACE_TCHAR); 20 ACE_TCHAR *report = 0; // Ask info() to allocate buffer. 21 int len = st->type ()->info (&report, 0);

22 iov[2].iov_base = ACE_static_cast (char *, report); 23 iov[2].iov_len = ACE_static_cast (size_t, len);

24 iov[2].iov_len *= sizeof (ACE_TCHAR);

25 peer_stream.sendv_n (iov, 3);

26 ACE::strdelete (report);

27 }

28

29 peer_stream.close ();

30 return 0;

31 }

Lines 2? Accept a new client connection. The Service_Reporter is an iterative service that only handles one client at a time.

Lines 5? Initialize an ACE_Service_Repository_Iterator, which we'll use to report all the active and suspended services offered by the server. Passing a 0 as thesecond argument to this constructor instructs it to also return information on suspended services, which are ignored by default.

Lines 8?7 For each service, invoke its info() method to obtain a descriptive

synopsis of the service, and send this information back to the client via the connectesocket. The sendv_n() gather-write method transfers all data buffers in the array oiovec structures efficiently using a single system function call, as discussed by Sidebar 6 in Chapter 3 of C++NPv1. Since there are no record boundaries in a TCPstream, the client may not be able to find the end of each line of text. It's therefore polite to code info() methods to include a newline at the end of the message. Notethat this code can work with either narrow or wide characters, as discussed in (page 121). The text received by the client will be in the character set and width the Service_Reporter. Designing a mechanism to handle this properly is left as anexercise for the reader.

Line 29 Close down the connection to the client and release the socket handle.

The Service_Reporter::info() hook method passes back a string that tells whicTCP port number it's listening on and what the service does:

关于ACE的详细介绍,ACE是一种跨平台的网络编程框架

int Service_Reporter::info (ACE_TCHAR **bufferp,

size_t length) const {

ACE_INET_Addr local_addr;

acceptor_.get_local_addr (local_addr);

ACE_TCHAR buf[BUFSIZ];

ACE_OS::sprintf

(buf, ACE_TEXT ("%hu"), local_addr.get_port_number ()); ACE_OS_String::strcat

(buf, ACE_TEXT ("/tcp # lists services in daemon\n")); if (*bufferp == 0) *bufferp = ACE::strnew (buf);

else ACE_OS_String::strncpy (*bufferp, buf, length);

return ACE_OS_String::strlen (*bufferp);

}

As with the Reactor_Logging_Server_Adapter::info() method (page 124), thcaller must delete the dynamically allocated buffer using ACE::strdelete().

The Service_Reporter's suspend() and resume() hook methods forward to thecorresponding methods in the reactor singleton, as follows:

int Service_Reporter::suspend ()

{ return reactor ()->suspend_handler (this); }

int Service_Reporter::resume ()

{ return reactor ()->resume_handler (this); }

The Service_Reporter::fini() method is shown below:

int Service_Reporter::fini () {

reactor ()->remove_handler

(this,

ACE_Event_Handler::ACCEPT_MASK

| ACE_Event_Handler::DONT_CALL);

return acceptor_.close ();

}

This method closes the ACE_SOCK_Acceptor endpoint and removes the

Service_Reporter from the singleton reactor. The ACE Service Configurator

framework is responsible for deleting a service object after calling its fini() hook method. We therefore don't need to delete this object in handle_close(), so wpass the DONT_CALL flag to prevent the reactor from invoking this callback. Finally, we must supply the ACE Service Configurator framework with some

"bookkeeping" information regarding this new service. Although the code for this service will be statically linked into the example program, we want the framework toinstantiate a Service_Reporter object to execute the service when it's activated. We therefore add the necessary ACE service macros to the Service_Reporter implementation file. These macros create a Service_Reporter and register it with the ACE_Service_Repository, as described in Sidebar 32 (page 136).

本文来源:https://www.bwwdw.com/article/n1u1.html

Top