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 ...
随机推荐
- webapi 解决ajax跨域请求问题
webapi在配置文件中加入这几句就可以解决ajax(同源策略是JavaScript里面的限制,其他的编程语言,比如在C#,Java或者iOS等其他语言中是可以调用外部的WebService,也就是 ...
- src url href uri的区别和联系
- Working with Binary Data in Python
http://www.devdungeon.com/content/working-binary-data-python
- GZAPI框架初识
新建一个MVC项目(GZAPIFramework.Demo): mvc:用于API接口文档查看,Log日志查看 webapi:api调用 新建一个Biz类库并添加nuget引用: 搜索GZAPI.Co ...
- 用HttpSessionListener与HttpSessionBindingListener实现在线人数统计
在线人数统计方面的实现,最初我的想法是,管理session,如果session销毁了就减少,如果登陆用户了就新增一个,但是如果是用户非法退出,如:未注销,关闭浏览器等,这个用户的session是管理不 ...
- cpp blog上面看到一哥们写的 下拉列表
#ifndef DROPDOWNLIST_H_INCLUDED#define DROPDOWNLIST_H_INCLUDED namespace azl{ #define DROPDOWNLIST_N ...
- TCP/IP协议学习(三) STM32中ETH驱动配置注意事项
1.MII/RMII/SMI接口连接和配置 SMI又称站点管理接口,用于cpu与外置PHY芯片通讯,配置相关参数,包含MDC和MDIO两个管脚(CPU上有对应引脚,当然用普通GPIO口模拟SMI管理也 ...
- Deep Learning 16:用自编码器对数据进行降维_读论文“Reducing the Dimensionality of Data with Neural Networks”的笔记
前言 论文“Reducing the Dimensionality of Data with Neural Networks”是深度学习鼻祖hinton于2006年发表于<SCIENCE > ...
- 中国Linux源镜像站大全
原文链接:http://www.centoscn.com/yunwei/news/2012/1227/131.html 一.国内的linux源镜像站点: 1.企业源:阿里云开源镜像站: http:// ...
- Oracle10g_Dataguard__161031
1.查看 redo log 信息 1.1.desc v$log ZC: 不明白这是查看什么信息... 1.2. 查看redo log file SQL> select * from v$log ...