现在的位置: 首页 > 综合 > 正文

ACE之旅——Acceptor-Connector框架实例

2012年12月04日 ⁄ 综合 ⁄ 共 3680字 ⁄ 字号 评论关闭

ACE之旅——Acceptor-Connector框架实例

  ACE的Reactor框架非常方便,结合Acceptor-Connector更为方便。以下是一个使用Acceptor-Connector框架写的daytime实例C/S应用。

svr.cpp

#include "ace/INET_Addr.h"
#include
"ace/SOCK_Stream.h"
#include
"ace/SOCK_Acceptor.h"
#include
"ace/Log_Msg.h"
#include
"ace/Acceptor.h"
#include
"ace/Svc_Handler.h"
#include
<time.h>

class ClientService;

typedef ACE_Acceptor
<ClientService, ACE_SOCK_ACCEPTOR> ClientAcceptor;

class ClientService : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> {
typedef ACE_Svc_Handler
<ACE_SOCK_STREAM, ACE_NULL_SYNCH> super;
public:
int open(void *);
virtual int handle_output(ACE_HANDLE fd = ACE_INVALID_HANDLE);
};

int ClientService::open(void *p) {
if (super::open(p) == -1)
return -1;

ACE_TCHAR peer_name[MAXHOSTNAMELEN];
ACE_INET_Addr peer_addr;
if (this->peer().get_remote_addr(peer_addr) == 0 && peer_addr.addr_to_string(peer_name, MAXHOSTNAMELEN) == 0)
ACE_DEBUG((LM_DEBUG, ACE_TEXT(
"(%P|%t) Connection from %s\n"), peer_name));

return this->reactor()->register_handler(this, ACE_Event_Handler::WRITE_MASK);
// return 0;
}

int ClientService::handle_output(ACE_HANDLE fd) {
ACE_TCHAR peer_name[MAXHOSTNAMELEN];
ACE_INET_Addr peer_addr;

this->peer().get_remote_addr(peer_addr);
peer_addr.addr_to_string(peer_name, MAXHOSTNAMELEN);

ACE_DEBUG((LM_DEBUG, ACE_TEXT(
"(%P|%t) in ClientService::handle_output Connectionfrom %s\n"), peer_name));

time_t ticks
= time(NULL);
char timeBuf[128];

memset(timeBuf,
0, sizeof(timeBuf));
ACE_OS::snprintf(timeBuf,
sizeof(timeBuf), "%.24s\r\n", ctime(&ticks));
ACE_OS::printf(
"output=[%s]\n", timeBuf);
this->peer().send_n(timeBuf, ACE_OS::strlen(timeBuf));

this->reactor()->remove_handler(this, ACE_Event_Handler::NULL_MASK);

return 0;
}

int ACE_TMAIN(int, ACE_TCHAR *[]) {
ACE_INET_Addr port_to_listen(
"50000");
ClientAcceptor acceptor;
// acceptor.reactor(ACE_Reactor::instance());
if (acceptor.open(port_to_listen) == -1)
return 1;

ACE_Reactor::instance()
->run_reactor_event_loop();

return 0;
}
  • Acceptor-Connector框架大概的运行过程就是每个连接的客户端对应服务端一个ClientService对象,这个ClientService对象必须是从ACE_Svc_Handler派生的,当Acceptor接到连接请求并建立好该连接之后会创建ACE_Acceptor模板参数ClientService类的对象,并调用该对象的open方法,该方法默认只会添加READ事件到Reactor,需要监听WRITE事件,需要手动调用register_handler。
  • 请注意带下划线的那行,因为daytime服务器没有从客户端接受任何输入,只是将信息发往客户端,所以如果只是简单的重写了handle_output方法,ACE_Reactor默认是用select实现的,水平触发的select会在短时间内多次出发WRITE事件,只要输出缓冲区未满,所以加下划线的那行的作用就是给客户端发送完后就让Reactor不再监听WRITE,并关闭该连接,即调用handle_close。当然这种方法在单线程情况下有效,如果多线程的情况应该需要加锁。

  以下为daytime的客户端部分,ACE_Connector和ACE_Acceptor的运行过程类似

cli.cpp

#include "ace/INET_Addr.h"
#include
"ace/Connector.h"
#include
"ace/Log_Msg.h"
#include
"ace/Svc_Handler.h"
#include
"ace/SOCK_Connector.h"

class Client : public ACE_Svc_Handler <ACE_SOCK_STREAM, ACE_NULL_SYNCH> {
typedef ACE_Svc_Handler
<ACE_SOCK_STREAM, ACE_NULL_SYNCH> super;
public:
int handle_input(ACE_HANDLE);
};

int Client::handle_input(ACE_HANDLE fd) {
int bc;
char buf[64];
ACE_OS::memset(buf,
0, sizeof(buf));
bc
= this->peer().recv(buf, sizeof(buf));
ACE_Reactor::instance()
->end_reactor_event_loop();
write(
1, buf, bc);
return 0;
}

int ACE_TMAIN(int, ACE_TCHAR *[]) {
ACE_INET_Addr svr(
50000, ACE_LOCALHOST);
ACE_Connector
<Client, ACE_SOCK_CONNECTOR> connector;
Client cli;
Client
*pc = &cli;
if (connector.connect(pc, svr) == -1)
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT(
"%p\n"), ACE_TEXT("connect")), 1);

ACE_Reactor::instance()
->run_reactor_event_loop();

return 0;
}
  • 在接受完数据后调用Reactor的end_reactor_event_loop方法,结束Reactor监听循环。

  以下是编译这两个程序的makefile

CC= g++
INCL = $(ACE_ROOT)/include
LIBS = $(ACE_ROOT)/lib

reac_cli_deps = reac_cli.cpp
reac_svr_deps = reac_svr.cpp

.SUFFIXES: .cpp.o
.cpp.o:
    $(CC) -g -I$(INCL) -c $*.cpp

all: reac_cli reac_svr

reac_cli: $(reac_cli_deps)
    $(CC) -g -I$(INCL) -L$(LIBS) -o reac_cli $(reac_cli_deps) -lACE
reac_svr: $(reac_svr_deps)
    $(CC) -g -I$(INCL) -L$(LIBS) -o reac_svr $(reac_svr_deps) -lACE

clean:
    -rm *~
    -rm reac_cli
    -rm reac_svr

(转载时请注明作者和出处。未经许可,请勿用于商业用途)
  更多文章请访问我的Blog: http://www.cnblogs.com/logicbaby

抱歉!评论已关闭.