简单的ACE反应器(Reactor)模式服务器
2015-11-15 11:22
513 查看
在服务器端使用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:`
先解释三个成员变量, 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:
下面为Cli_acceptor.h:
成员变量为一个ACE_SOCK_Acceptor对象,来完成实际的监听工作和接收连接。
handle_input(),handle_close(),get_handle()就不说了。
get_Acceptor()可以忽略
open():这个函数执行bind(),listen()操作,其实就是实际执行acceptor.open()函数
下面为Cli_acceptor.cpp:
好了两个类已经介绍完了,下面就是main()函数中的内容,当你完成两个类后,就会发现,main()函数很好写,下面为ser.cpp:
ACE的事件注册,我大概有一个猜想,但是我不敢肯定,我会查找一些资料再说
使用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的事件注册,我大概有一个猜想,但是我不敢肯定,我会查找一些资料再说
相关文章推荐
- ReactiveCocoa入门教程——第二部分
- muduo的reactor模式基本实现
- React-Native尝鲜计划-环境搭建及 hello world
- ReactiveCocoa入门教程——第一部分
- React Native 中Image 加本地图片的方法
- react学习
- ReactiveCocoa & MVVM
- react native 生成apk
- React with Webpack - 3: 内联image、font
- React学习--使用babel
- react native Text 上无法指定borderWidth 等一系列属性
- React with Webpack - 2: css 处理
- React 当前组件与当前函数交互
- React Native通信机制详解【转】
- react 学习
- 一个资深iOS开发者对于React Native的看法
- ReAct 常用 的属性
- muduo库阅读(29)——Net部分:Reactor(EventLoop事件循环)
- React-Native学习指南
- 现有的iOS项目集成ReactNative的记录文档