在服务器端使用Reactor框架
使用Reactor框架的服务器端结构如下:
服务器端注册两种事件处理器,Cli_acceptor和Cli_server ,Cli_server类负责和客户端的通信,每一个Cli_server对象对应一个客户端的Socket连接。 Cli_acceptor专门负责被动接受客户端的连接,并创建Cli_server对象。这样,在一个N个Socket连接的服务器程序中,将存在1个Cli_acceptor对象和N个Cli_server对象。
整个服务器端流程如下:
首先创建一个Cli_acceptor对象,该对象在Reactor上注册ACCEPT_MASK事件,Reactor将自动在监听端口建立Socket监听。
如果有对该端口的Socket连接时,Reactor将自动回调handle_input方法,Cli_acceptor重载此方法,并创建一个Cli_server对象,用于处理和Client的通信。
Cli_server对象根据服务器的具体功能实现,其处理过程和客户端程序类似,注册相应的回调事件并分发即可。
下面为Cli_server.h:`
#ifndef GGGGG
#define GGGGG
#include"ace/Event_Handler.h"
#include"ace/Log_Msg.h"
#include"ace/SOCK_Stream.h"
#include"ace/Reactor.h"
class Cli_server : public ACE_Event_Handler
{
public:
Cli_server();
~Cli_server();
const ACE_SOCK_Stream &get_Stream();
void set_ptr(Cli_server*);
void set_Stream(const ACE_SOCK_Stream peer);
int register_read();
virtual int handle_input(ACE_HANDLE fd);
virtual ACE_HANDLE get_handle() const;
virtual int handle_close(ACE_HANDLE ,ACE_Reactor_Mask close_mask);
private:
ACE_SOCK_Stream peer;
Cli_server *cliser;
bool nd_dt;
};
#endif`
先解释三个成员变量, peer负责真正的通信,cliser和nd_dt是为了释放资源(可能我用的是虚拟机,ACE中的智能指针貌似用不了,只能手动释放资源),若果nd_dt为true,就需要释放。这个到用的时候会详细解释。
构造函数和析构函数就不说了。
get_Stream():函数可以省略不管,没什么用。
set_Stream():用来设置peer的值,这个函数用一个ACE_SOCK_Stream对象作为参数,注意这个 按值传递,具体原因后面会解释。
register_read():用来注册读事件,将peer的读事件注册到反应器。
handle_input():十分重要的函数,当我们注册的事件发生时,会调用这个函数。这个函数从父类
ACE_Event_Handler继承而来,你必须重写它。
handle_close():在其他handle_*()挂钩方法中的一个返回-1时,或是在ACE_Reactor::remove_handler()被显式调用来解除事件处理器的登记时,执行用户定义的终止活动的挂钩方法
get_handle():这个函数同handle_input()继承自父类,你必须重载它,这个函数后面的const修饰词必须加上(C++多态,方法后是否有const也是一种重载),这个函数会在注册的时候用上,这个函数返回实际的I/O handle,我们这个类即返回peer的handle
下面为Cli_server.cpp:
#include"Cli_server.h"
const ACE_SOCK_Stream& Cli_server::get_Stream() //可以忽略
{
ACE_DEBUG((LM_DEBUG,ACE_TEXT("get_Stream() : \n")));
return peer;
}
void Cli_server::set_Stream(const ACE_SOCK_Stream peer)
{
ACE_DEBUG((LM_DEBUG,ACE_TEXT("set_Stream() : \n")));
this->peer=peer; //peer赋值,按值传递
}
int Cli_server::register_read()
{
ACE_DEBUG((LM_DEBUG,ACE_TEXT("register_read() : \n")));
return ACE_Reactor::instance()->register_handler(this,ACE_Event_Handler::READ_MASK);
//注册读事件,在这个函数执行中,会调用this->get_handle()这个语句,将实际的handle与事件 相关联,若get_handle()函数返回错误的handle或者后面没有const修饰词,就会造成注册失败
}
ACE_HANDLE Cli_server::get_handle() const
{
return peer.get_handle();//返回peer的handle,即实际做事情的handle
}
int Cli_server::handle_input(ACE_HANDLE fd)
{
char recvbuf[100]={}; //测试用代码,这个可以随意写
if(peer.recv(recvbuf,sizeof(recvbuf))<0)
{
ACE_DEBUG((LM_ERROR,ACE_TEXT("recv error ! \n")));
return -1;
}
char sendbuf[20]="hello world!";
peer.send_n(sendbuf,sizeof(sendbuf));
return 0;
}
int Cli_server::handle_close(ACE_HANDLE handle,ACE_Reactor_Mask close_mask)
{
close_mask=ACE_Event_Handler::ALL_EVENTS_MASK | ACE_Event_Handler::DONT_CALL;
this->reactor()->remove_handler(this,close_mask);
peer.close();
return 0;
}
Cli_server::Cli_server():cliser(NULL),nd_dt(false)
{
}
void Cli_server::set_ptr(Cli_server * ptr)
{
nd_dt=true; //这个函数是为了释放内存
cliser=ptr;
}
Cli_server::~Cli_server()
{
if(nd_dt)
delete cliser; //释放内存
}
下面为Cli_acceptor.h:
#ifndef HHHHHHHHHHHHHH
#define HHHHHHHHHHHHHH
#include"ace/Log_Msg.h"
#include"ace/Event_Handler.h"
#include"ace/SOCK_Acceptor.h"
#include"ace/INET_Addr.h"
#include"Cli_server.h"
#include<memory>
class Cli_acceptor : public ACE_Event_Handler
{
public:
~Cli_acceptor();
const ACE_SOCK_Acceptor& get_Acceptor();
void set_Acceptor(const ACE_SOCK_Acceptor& );
virtual ACE_HANDLE get_handle() const;
int open(const ACE_INET_Addr &);
virtual int handle_input(ACE_HANDLE);
virtual int handle_close(ACE_HANDLE,ACE_Reactor_Mask);
private:
ACE_SOCK_Acceptor acceptor;
};
#endif
成员变量为一个ACE_SOCK_Acceptor对象,来完成实际的监听工作和接收连接。
handle_input(),handle_close(),get_handle()就不说了。
get_Acceptor()可以忽略
open():这个函数执行bind(),listen()操作,其实就是实际执行acceptor.open()函数
下面为Cli_acceptor.cpp:
#include"Cli_acceptor.h"
const ACE_SOCK_Acceptor& Cli_acceptor::get_Acceptor()
{
return acceptor;
}
void Cli_acceptor::set_Acceptor(const ACE_SOCK_Acceptor&acceptor)
{
this->acceptor=acceptor;
}
int Cli_acceptor::open(const ACE_INET_Addr &addr)
{
if(acceptor.open(addr,1)==-1) //执行acceptor.open()函数
{
ACE_DEBUG((LM_ERROR,ACE_TEXT("Cli_acceptor :: open error!\n")));
return -1;
}
return ACE_Reactor::instance()->register_handler(this,ACE_Event_Handler::ACCEPT_MASK);
//注册事件
}
int Cli_acceptor::handle_input(ACE_HANDLE fd)
{
ACE_SOCK_Stream peer; //这里就是为什么传值而不是传引用,若为引用的话这里就必须为一个指针或者静态变量,但都不符合要求。(智能指针我电脑不能用,静态变量,呵呵)所以这里我用的是传值,当然这里最后用指针动态分配,你们可以自己试一下
if(acceptor.accept(peer)!=0)
{
ACE_DEBUG((LM_ERROR,ACE_TEXT("ACE_acceptor :: handle_input error!\n")));
return -1;
}
Cli_server *cliser=new Cli_server; //这个。一个连接对应一个Cli_server对象,这个必须要动态生成了,但是没有地方释放资源,所以就有了set_ptr()这个函数和那两个成员变量,就是为了释放这里的资源
cliser->set_ptr(cliser);
cliser->set_Stream(peer);//设置peer
cliser->register_read();//注册读事件
return 0;
}
int Cli_acceptor::handle_close(ACE_HANDLE handle,ACE_Reactor_Mask close_mask)
{
close_mask=ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL;
this->reactor()->remove_handler(this,close_mask);
acceptor.close();
}
Cli_acceptor::~Cli_acceptor()
{
this->handle_close(ACE_INVALID_HANDLE,0);
}
ACE_HANDLE Cli_acceptor::get_handle() const
{
return acceptor.get_handle();
}
好了两个类已经介绍完了,下面就是main()函数中的内容,当你完成两个类后,就会发现,main()函数很好写,下面为ser.cpp:
#include"ace/Log_Msg.h"
#include"ace/SOCK_Acceptor.h"
#include"ace/SOCK_Stream.h"
#include"ace/INET_Addr.h"
#include"ace/Reactor.h"
#include"ace/SOCK_Connector.h"
#include"Cli_acceptor.h"
int ACE_TMAIN(int argc,ACE_TCHAR**argv)
{
Cli_acceptor acceptor; //一个接受连接的对象
ACE_INET_Addr addr(6666); //IP地址
acceptor.open(addr); //完成bind()和listen()
while(1)
ACE_Reactor::instance()->handle_events();//激发事件轮询
return 1;
}
ACE的事件注册,我大概有一个猜想,但是我不敢肯定,我会查找一些资料再说