Ace tips: create a custom service processor in the ace_acceptor framework
Stone Jiang
The ace_acceptor framework makes listening for new connections easy, and also makes it easy to create and activate the derived class of ace_svc_handler for new connections. We have learned about the role of the ace_svc_handle: open () Hook Function and the service processor during initialization. In this article, we take a few steps back to understand how the service processor is instantiated and how we customize its behavior.
Take a look at the ace_acceptor class, which is a template class. The first template parameter ace_accetpor represents the processor that establishes a connection with the service. When a new connection is established, ace_acceptor calls the make_svc_handler () Hook Function to create a new service processor object. Ace_acceptor: make_svc_handler () is implemented as follows:
Template <class svc_handle, ace_peer_acceptor_1>
Int
Ace_acceptor <svc_handle, ace_peer_acceptor_2 >:: make_svc_handler (svc_handle * & SH)
{
Ace_trace ("ace_acceptor <svc_handler, ace_peer_acceptor_2 >:: make_svc_handler"); If (SH = 0)
Ace_new_return (Sh,
Svc_handler,
-1); // set the reactor of the newly created <svc_handler> to the same
// Reactor that this <ace_acceptor> is using.
Sh-> Reactor (this-> Reactor ());
Return 0;
}
The default implementation includes two basic operations:
1. Get a new svc_hanlder object, which is allocated using the new operator.
2. Set the reactor pointer of the new service processor to the reactor used by ace_accetpor.
However, what should I do if the application needs to obtain the svc_handler object in other ways, instead of the dynamic allocation through the default constructor? For example, we may need:
. Obtain the svc_handler object from a pre-allocated pool;
. Pass in some additional information for the newly created svc_handler.
. Use a standalone svc_handler
In the above cases, we can customize the make_svc_handler () Hook Function to implement the necessary behavior. For example, assume that our new processor needs to have a central processor that processes all received messages in a centralized manner. This core processor is represented by a processor class. We need each service processor to have a pointer to the central processor, instead of making processor A Global Access pointer (the disadvantages of using global variables are not described in detail in this article ). Our solution is to derive a new class from ace_accetor, which has the processor pointer as a member and, when creating a new and service processor (service, pass the processor pointer as a parameter.
The new acceptor class can be defined as follows:
Class my_acceptor: Public ace_acceptor <service, ace_sock_acceptor>
...{
Public:
My_acceptor (processor * processor): processor _ (processor )...{};
Int make_svc_handler (Service * & SH)
...{
If (SH = 0)
Ace_new_return (Sh,
Service (this-> processor _),
-1); // set the reactor of the newly created <svc_handler> to the same
// Reactor that this <ace_acceptor> is using.
Sh-> Reactor (this-> Reactor ());
Return 0;
}
PRIVATE:
Processor * processor _;
}
Now, when my_acceptor accepts a new connection, the make_svc_handler () hook function allocates a new processor (service) and transmits processor * as a parameter. Please note that, even if you use
Is this constructor Service (processor *). We still need to define the default constructor for the service class to meet the needs of the template class ace_acceptor.