ACE - Reactor实现I/O,Dispatch,Service三层完整服务器(完结)
框架描述
服务器层次:
- I/O层:对应具体的文件描述符处理,对应ACE中的handle。
- Dispatch层:事件分发,将I/O事件分发到对应绑定的处理队列等待业务处理,对应ACE中的Event_handle。
- 业务层:处理具体业务,包含一组线程或进程,并发处理业务。对应ACE中的ACE_Task。
三层结构与五层网络的网络层,传输层,应用层类似对应。
Reactor模式:
- I/O处理:ACE_Reactor使用select复用完成,将注册进去的IOhandle进行事件监听。
- 消息队列:ACE_Task中包含一个消息队列。I/O产生事件后执行绑定的Event函数将消息插入对应的消息队列。
- 服务进程:ACE_Task内可以构造一个线程池,获取消息队列进行业务并发处理。
下面是Reactor代码实现,包含I/O、dispatch、反应器、和线程池:
/*-----------------------------------------------------------------
* filename: Reactor.cpp
* author: bing
* time: 2016-06-29 15:26
* function: using ACE Reactor implement I/O multiplex server,
* include service thread pool.
*-----------------------------------------------------------------*/
#include <ace/INET_Addr.h>
#include <ace/SOCK_Acceptor.h>
#include <ace/SOCK_Stream.h>
#include <ace/Reactor.h>
#include <ace/Log_Msg.h>
#include "ace/Task.h"
#include "ace/OS.h"
#include <list> #define MAX_BUFF_SIZE 1024
#define LISTEN_PORT 5010
#define SERVER_IP ACE_LOCALHOST
#define THREAD_NUM 10 struct MsgData
{
ACE_HANDLE* IOHandle;
int DataFlag;
char Data[MAX_BUFF_SIZE];
MsgData()
{
IOHandle = NULL;
DataFlag = -;
ACE_OS::memset(Data, , sizeof(Data));
}
}; class TaskThread; class ServerStream : public ACE_Event_Handler
{
public:
ServerStream(TaskThread* pMsgQueue);
~ServerStream();
ACE_SOCK_Stream& GetStream(){return m_Svr_stream;} //给accept提供接口绑定数据通道
virtual int handle_input(ACE_HANDLE fd); //I/O触发事件后调用
void close();
virtual ACE_HANDLE get_handle(void) const {return m_Svr_stream.get_handle();} //不重载需要手动将handle传入ACE_Reactor
private:
ACE_SOCK_Stream m_Svr_stream;
TaskThread* m_MsgQueue;
}; std::list<ServerStream*> g_StreamPool; //stream pool class TaskThread: public ACE_Task<ACE_MT_SYNCH>
{
public:
virtual int svc(void)
{
ACE_Message_Block *Msg;// = new ACE_Message_Block();
while()
{
getq(Msg); //空闲线程阻塞 ACE_Data_Block *Data_Block = Msg->data_block();
MsgData *pData = reinterpret_cast <MsgData*>(Data_Block->base());
if ( == pData->DataFlag)
{
std::list<ServerStream*>::iterator it;
for (it = g_StreamPool.begin();it != g_StreamPool.end();++it)
{
if (get_handle() == (*it)->get_handle())
{
g_StreamPool.erase(it);
delete *it;
break;
}
}
return ;
}
char strBuffer[MAX_BUFF_SIZE];
ACE_OS::memset(strBuffer, , sizeof(strBuffer));
ACE_OS::memcpy(strBuffer, pData->Data, sizeof(strBuffer));
/*
这里接口业务代码分发数据
*/
ACE_DEBUG((LM_INFO,"[time:%d]recevie msg:%s\n",(int)ACE_OS::time(),strBuffer));
//ACE_SOCK_Stream Stream(*(pData->IOHandle));
//Stream.send("server recive data!\n",sizeof("server recive data!")); //响应client数据
//ACE_OS::sleep(1); //模拟业务耗时
Msg->release(); //release,inclue data_block
//ACE_DEBUG((LM_INFO,"thread end queue count:%d\n",msg_queue_->message_count()));
}
return ;
}
};
typedef ACE_Singleton<TaskThread, ACE_Thread_Mutex> TaskThreadPool; ServerStream::ServerStream(TaskThread* pMsgQueue)
{
m_MsgQueue = pMsgQueue;
} ServerStream::~ServerStream()
{
close();
} /*------------------------------------------------------
* IO上报流数据,使用select复用上报,这里单线程处理
* 原来考虑直接把IO插队列给线程池处理,但是线程池和
* 这里是异步操作,线程没有处理队列这条消息ACE底层会
* 一直上报这个IO插消息队列,暂时在这里做单线程revc
* 考虑epoll边沿触发,一次上报处理
*------------------------------------------------------*/
int ServerStream::handle_input(ACE_HANDLE fd)
{
MsgData Message;
char strBuffer[MAX_BUFF_SIZE];
Message.DataFlag = m_Svr_stream.recv(strBuffer,MAX_BUFF_SIZE); //获取数据回select响应避免反复通知
if (- == Message.DataFlag)
{
ACE_DEBUG((LM_INFO, ACE_TEXT("recive data error!\n")));
return -;
}
else if( == Message.DataFlag)
{
close();
ACE_DEBUG((LM_INFO, ACE_TEXT("client closed!\n")));
}
ACE_Data_Block *Data_Block = new ACE_Data_Block; //线程做释放
ACE_HANDLE Cli_IO = get_handle(); Message.IOHandle = &Cli_IO;
ACE_OS::memcpy(Message.Data,strBuffer,sizeof(strBuffer));//传的data可带length信息来适配消息大小 char *p = reinterpret_cast <char*>(&Message);
Data_Block->base(p,sizeof(Message));
ACE_Message_Block* msg = new ACE_Message_Block(Data_Block);
m_MsgQueue->putq(msg); //put
//Data_Block->release();
return ;
} void ServerStream::close()
{
m_Svr_stream.close();
ACE_Reactor::instance()->remove_handler(this,ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL);
} class ServerAcceptor : public ACE_Event_Handler
{
public:
ServerAcceptor(int port,char* ip);
~ServerAcceptor();
bool open();
virtual int handle_input(ACE_HANDLE fd); //有client连接
void close();
virtual ACE_HANDLE get_handle(void) const {return m_Svr_aceept.get_handle();}
private:
ACE_INET_Addr m_Svr_addr;
ACE_SOCK_Acceptor m_Svr_aceept;
}; ServerAcceptor::ServerAcceptor(int port,char* ip):m_Svr_addr(port,ip)
{
if (!open()) //open listen port
{
ACE_DEBUG((LM_INFO, ACE_TEXT("open failed!\n")));
}
else
{
ACE_DEBUG((LM_INFO, ACE_TEXT("open success!\n")));
TaskThreadPool::instance()->activate(THR_NEW_LWP | THR_JOINABLE |THR_INHERIT_SCHED , THREAD_NUM);//创建10个线程处理业务
}
} ServerAcceptor::~ServerAcceptor()
{
close();
std::list<ServerStream*>::iterator it;
for (it = g_StreamPool.begin();it != g_StreamPool.end();++it)
{
if (NULL != (*it))
{
(*it)->close();
delete (*it);
}
}
} bool ServerAcceptor::open()
{
if (- == m_Svr_aceept.open(m_Svr_addr,))
{
ACE_DEBUG((LM_ERROR,ACE_TEXT("failed to accept\n")));
m_Svr_aceept.close();
return false;
}
return true;
} int ServerAcceptor::handle_input(ACE_HANDLE fd )
{
ServerStream *stream = new ServerStream(TaskThreadPool::instance()); //产生新通道
if (NULL != stream)
{
g_StreamPool.push_back(stream);//暂时存储全局变量用于内存管理,优化可增加一个连接管理类管理连接通道
}
if (m_Svr_aceept.accept(stream->GetStream()) == -) //绑定通道
{
printf("accept client fail\n");
return -;
}
ACE_Reactor::instance()->register_handler(stream,ACE_Event_Handler::READ_MASK); //通道注册到ACE_Reactor
ACE_DEBUG((LM_INFO,"User connect success!,ClientPool num = %d\n",g_StreamPool.size()));
return ;
} void ServerAcceptor::close()
{
ACE_Reactor::instance()->remove_handler(this,ACE_Event_Handler::ACCEPT_MASK);
m_Svr_aceept.close();
} int ACE_TMAIN()
{
ServerAcceptor server(LISTEN_PORT,(char *)SERVER_IP);
ACE_Reactor::instance()->register_handler(&server,ACE_Event_Handler::ACCEPT_MASK); //listen port注册到ACE_Reactor ACE_Reactor::instance()->run_reactor_event_loop(); //进入消息循环,有I/O事件回调handle_input
return ;
}
代码实现了最简单的完整并发服务器,有部分还值得思考和优化:
1.dispatch进行类封装
2.回话通道的数据流管理进行类封装
3.dispatch消息结构优化
4.dispatch处为单线程,直接传递I/O给线程获取数据流还是获取数据流完成后给线程,如何实现两个线程同步
5.底层I/O复用使用epoll边沿优化
6.业务buff处理优化,进行消息类型划分,进入不同业务处理
由于实现完整服务器代码以最简单形式实现,上述优化在实际商用代码中还需要大量封装优化考虑。
ACE - Reactor实现I/O,Dispatch,Service三层完整服务器(完结)的更多相关文章
- ACE - Reactor模式源码剖析及具体实现(大量源码慎入)
原文出自http://www.cnblogs.com/binchen-china,禁止转载. 在之前的文章中提到过Reactor模式和Preactor模式,现在利用ACE的Reactor来实现一个基于 ...
- ACE - Reactor源码总结整理
ACE源码约10万行,是c++中非常大的一个网络编程代码库,包含了网络编程的边边角角. ACE代码可以分三个层次:OS层.OO层和框架层: OS层主要是为了兼容各个平台,将网络底层API统一化,这一层 ...
- ACE Reactor 源码解析
http://blogs.readthedocs.org/ ACE的学习笔记,根据源码分析了Reactor模型的实现. 因为笔记编写技术限制,这里仅列出主要目录,如有可能可以抽空复制到该Blog中 ...
- Dao、Controller、Service三层的结构划分
Java Web基础--Controller+Service +Dao三层的功能划分(摘取自网络)1. Controller/Service/DAO简介: Controller是管理业务( ...
- xml、 Dao service 三层参数以及对应关系
=======service 调用dao用params.put(K,Value);将参数传入后台. BaseResponse response = new BaseResponse(); Map& ...
- 部署基于国际版Azure的SharePoint三层架构服务器场
前言 微软Azure国际版已经很普及了,这里没有用国内版(世纪互联),用的是国际版,当然是由于公司性质的缘故.这里一步步图文的方式,分享给大家创建Azure国际版的SharePoint三层架构的过程, ...
- [CareerCup] 10.1 Client-facing Service 面向客户服务器
10.1 Imagine you are building some sort of service that will be called by up to 1000 client applicat ...
- Reporting Service 2008 “报表服务器数据库内出错。此错误可能是因连接失败、超时或数据库中磁盘空间不足而导致的”
今天遇到了两个关于Reporting Service的问题, 出现问题的环境为Microsoft SQL Server 2008 R2 (SP2) - 10.50.4000.0 (X64) .具体情况 ...
- 云计算之路-试用Azure:上不了高速的跑车,无法跨Cloud Service的DNS服务器
从阿里云的踩坑大师,到Azure的抹黑大师,我们似乎成了云计算负面用户的典型,可是我们还是忍不住想表达自己真实的使用感受.如果有错误的地方,欢迎大家批评! 在Azure上建好虚拟网(Vitual Ne ...
随机推荐
- IntelliJ IDEA使用(1)——IDEA配置JDK
提前安装jdk,配置环境变量 一.配置jdk 1.依次点开File -->Project Structure,点击左侧标签页,点击SDKs 2.点击+号,选SDK 3.在弹出框选择jdk路径(我 ...
- jQuery表单元素非空验证
<script type="text/javascript"> $(function(){ /************* ...
- [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序处理并发
这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第十篇:为ASP.NET MVC应用程序 ...
- Http 状态码对照表
1xx 消息 1. 100 Continue 2. 101 Switching Protocol 3. 102 Processing 2xx 成功 1. 200 OK ...
- 【java】关于时间
import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; /** * Created b ...
- touch穿透
出现穿透的前提:上层绑定touch事件,下层绑定click事件. 解决方案:touchend绑定: e.preventDefault();$(下层).css("pointer-events& ...
- iOS - Mac 锁屏快捷键设置
Mac 锁屏快捷键设置 control + shift + Eject 锁屏快捷键 如果用户要离开电脑一段时间,可以选择直接把笔记本直接合上.但是这样原先在跑的进程就会挂起或者结束,如果正在下载,那么 ...
- Node.js在不同平台的安装方法步骤详解
Mac平台下搭建node.js开发平台 安装方式 1 步骤: 下载mac版的.pkg文件(简单直接和Windows差不多) 安装方式 2 步骤: 安装xcode(命令:xcode-select --i ...
- 华为WLAN产品介绍-05
无线AP与AC的区别 WLAN系统一般由AC(接入控制器)和AP(无线接入点)组成. 无线AP,为Access Point简称,一般翻译为“无线访问节点”,它是用于无线网络的无线交换机,也是无线网络的 ...
- css优雅降级和渐进增强
今天看前端公众号发布的文章,学到了几个新词 1.modernizr 2.@support 3.优雅降级 其中第三个“优雅降级”,如此文艺的名字居然还是第一次听到.度娘了一下,发现[优雅降级],[渐进增 ...