从这里开始,我们继续进行主程序循环。 在某种程度上,当我们这样做时,我们将从最终产品开始,但这是一段非常简单的代码,也是一个很好的起点。
主程序非常简单。 真正的工作是在ACE派生类中完成的。
Kirthika Parameswaran提供了教程1的摘要:
这是一个简单的日志服务器示例。 Reactor用于处理多个客户端请求,使用单个执行线程而不是每个客户端一个线程。 Reactor使用“回调”技术重新启动事件并将事件多路分离到向其注册的相应Event_Handler。 reactor运行在一个对所有传入事件进行处理的infinte事件循环中。
Logging_Acceptor侦听SERVER PORT地址并被动地等待请求到达。 Acceptor也是一个Event_Handler,并在Reactor中注册。 它只是Reactor的另一个Event_Handler,因此不需要特殊的处理。
一旦发生连接请求,Acceptor就接受它并建立连接。 reactor实例被传递给处理程序,以便它可以向Reactor注册。 它使用ACE_Event_Handler :: ACCEPT_MASK执行此操作。
Logging_Client是另一个Event_Handler,它实际上在handle_input()方法中处理客户端请求。 它还在Reactor中注册了ACE_Event_Handler :: READ_MASK。
Event_Handlers可以使用handle_close()方法从Reactor取消注册,也可以显式调用remove_handler()方法。
此服务器应用程序构建并成功执行,等待客户端请求到达。
仅供参考(来自道格):
ACCEPT_MASK在ACE_Event_Handler类中定义。 它用于通知Reactor您要注册一个事件处理程序,以被动地“接受”连接。
READ_MASK也在ACE_Event_Handler类中定义。 它用于通知Reactor您要注册一个事件处理程序,来“读取”已建立连接的数据。
// page02.html,v 1.14 2000/03/19 20:09:19 jcej Exp
/* Include the header file where our client acceptor is defined. */
#include "ace/Reactor.h"
/* For simplicity, we create our reactor in the global address space.
In later tutorials we will do something more clever and
appropriate. However, the purpose of this tutorial is to introduce a
connection acceptance and handling, not the full capabilities of a
reactor. */
ACE_Reactor *g_reactor;
/* Include the header where we define our acceptor object. An
acceptor is an abstraction that allows a server to "accept"
connections from clients. */
#include "acceptor.h"
/* A TCP/IP server can listen to only one port for connection
requests. Well-known services can always be found at the same
address. Lesser-known services are generally told where to listen by
a configuration file or command-line parameter. For this example,
we're satisfied with simply hard-coding a random but known value. */
static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
int
main (int, char *[])
{
/* Create a Reactor instance. Again, a global pointer isn't exactly
the best way to handle this but for the simple example here, it
will be OK. We'll get cute with it later. Note how we use the
ACE_NEW_RETURN macro, which returns 1 if operator new fails. */
ACE_NEW_RETURN (g_reactor,
ACE_Reactor,
1);
/* Like the Reactor, I'm skimming over the details of the ADDR
object. What it provides is an abstraction for addressing services
in the network. All we need to know at this point is that we are
creating an address object which specifies the TCP/IP port on
which the server will listen for new connection requests. */
ACE_INET_Addr addr (PORT);
Logging_Acceptor *peer_acceptor;
/* We now create an acceptor object. No connections will yet be
established because the object isn't "open for business" at this
time. Which brings us to the next line... */
ACE_NEW_RETURN (peer_acceptor,
Logging_Acceptor,
1);
/* where the acceptor object is opened. You'll find that most ACE
objects have to be open()ed before they're of any use to you. On
this open() call, we're telling the acceptor where to listen for
connections via the 'addr' object. We're also telling it that we
want it to be registered with our 'g_reactor' instance. */
if (peer_acceptor->open (addr, g_reactor) == -1 )
ACE_ERROR_RETURN ((LM_ERROR,
"Opening Acceptor\n"),
-1);
ACE_DEBUG ((LM_DEBUG,
"(%P|%t) starting up server logging daemon\n"));
/* The reactor's handle_events member function is responsible for
looking at all registered objects and invoking an appropriate
member function when anything of interest occurs. When an event is
processed, the handle_events function returns. In order to get all
events, we embed this in an infinite loop.
Since we put ourselves into an infinite loop, you'll need to
CTRL-C to exit the program. */
for (;;)
g_reactor->handle_events ();
return 0;
}
正如我所说,主程序非常简单:
- 为我们想要侦听的端口创建一个地址
- 创建一个侦听该地址的接受器
- 向反应器注册接受器以响应连接请求
- 输入无限循环以让reactor处理事件
在下一页中,我们将介绍接受器以及它如何响应新的连接请求。