框架描述

服务器层次:

  • 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三层完整服务器(完结)的更多相关文章

  1. ACE - Reactor模式源码剖析及具体实现(大量源码慎入)

    原文出自http://www.cnblogs.com/binchen-china,禁止转载. 在之前的文章中提到过Reactor模式和Preactor模式,现在利用ACE的Reactor来实现一个基于 ...

  2. ACE - Reactor源码总结整理

    ACE源码约10万行,是c++中非常大的一个网络编程代码库,包含了网络编程的边边角角. ACE代码可以分三个层次:OS层.OO层和框架层: OS层主要是为了兼容各个平台,将网络底层API统一化,这一层 ...

  3. ACE Reactor 源码解析

    http://blogs.readthedocs.org/   ACE的学习笔记,根据源码分析了Reactor模型的实现. 因为笔记编写技术限制,这里仅列出主要目录,如有可能可以抽空复制到该Blog中 ...

  4. Dao、Controller、Service三层的结构划分

     Java Web基础--Controller+Service +Dao三层的功能划分(摘取自网络)1. Controller/Service/DAO简介:      Controller是管理业务( ...

  5. xml、 Dao service 三层参数以及对应关系

    =======service   调用dao用params.put(K,Value);将参数传入后台. BaseResponse response = new BaseResponse(); Map& ...

  6. 部署基于国际版Azure的SharePoint三层架构服务器场

    前言 微软Azure国际版已经很普及了,这里没有用国内版(世纪互联),用的是国际版,当然是由于公司性质的缘故.这里一步步图文的方式,分享给大家创建Azure国际版的SharePoint三层架构的过程, ...

  7. [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 ...

  8. Reporting Service 2008 “报表服务器数据库内出错。此错误可能是因连接失败、超时或数据库中磁盘空间不足而导致的”

    今天遇到了两个关于Reporting Service的问题, 出现问题的环境为Microsoft SQL Server 2008 R2 (SP2) - 10.50.4000.0 (X64) .具体情况 ...

  9. 云计算之路-试用Azure:上不了高速的跑车,无法跨Cloud Service的DNS服务器

    从阿里云的踩坑大师,到Azure的抹黑大师,我们似乎成了云计算负面用户的典型,可是我们还是忍不住想表达自己真实的使用感受.如果有错误的地方,欢迎大家批评! 在Azure上建好虚拟网(Vitual Ne ...

随机推荐

  1. python之rabbitMQ篇

    一.RabbitMQ安装 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统,它遵循Mozilla Pulic License开源协议. MQ全称为Message Queue,消息队列 ...

  2. C# 4.0中dynamic的作用

    internal sealed class Coffee { public string GetName() { return "You selected Maxwell coffee.&q ...

  3. php实战正则表达式:验证手机号

    摘自http://www.tuicool.com/articles/MFNZRzu 本文通过逐步完善一个验证手机号的正则表达式来介绍了正则表达式中的 字符组 .量词 . 字符串起始/结束位置 . 分组 ...

  4. DataGridView单元格美化

          #region 重绘Column.Row           int _RowHeadWidth = 41;         ///            /// 重绘Column.Row ...

  5. mysql命令导出导入数据和结构

    在命令行下mysql的数据导出有个很好用命令mysqldump,它的参数有一大把,可以这样查看: mysqldump 最常用的: mysqldump -uroot -pmysql databasefo ...

  6. io流操作大全

    JAVA 中的IO流 一.流的概念        流(stream)的概念源于UNIX中管道(pipe)的概念.在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备.外部 ...

  7. String和StringBuffer、StringBuilder的区别

    目录: 1.String类的不可变性 2.用String的时候需要注意什么 3.String与StringBuilder的区别 4.StringBuilder和StringBuffer的区别 Stri ...

  8. USACO2016Splitting the Field分割牧场

    Description FJ的N头奶牛分别位于他二维的牧场的不同位置.FJ想用一个矩形栅栏围住这些牛(牛可以在栅栏边上),并使这个栅栏尽可能小.这个栅栏的边与x轴或y轴平行.不幸的是,FJ上个季度的牛 ...

  9. Gson手动序列化POJO(工具类)

    gson2.7版本 只是简单的工具类(练习所用): package pojo; import javax.xml.bind.annotation.XmlSeeAlso; import com.goog ...

  10. APIO2015 酱油记

    Day 0 昨天CTSC才比完,当然是要浪啦! 于是浪了一天...午饭都没吃... 晚饭...貌似也没吃... 晚上的时候觉得这样子浪不太好,还是要认真一下,打开bzoj,弃疗了...还是浪吧... ...