大半年前买了本ACE的C++NPv2,翻了一下感觉满篇理论概念,没有看下去,然后这半年继续实现了些网络程序,前几天再次捧起这本书,先用两天时间囫囵吞枣、一目十行的粗览了一遍,结合自己之前的网络编程经验,感觉到一些共鸣,又再慢慢的进行仔细的阅读,写下自己的阅读体会。
篇(一)主要针对ACE_Reactor(反应器、反应堆)。
首先,先介绍一下我项目中自己写的一个网络编程库,对比一下,可以很好理解这个ACE_Reactor。
我的这个库,代码主要跨Linux/Win32平台,因为没有需要,没在其他平台测试过。这个库没有涉及UI部分,只是用来编写服务器端,或者Linux/Win32的控制台程序。先拿两个类来对比ACE_Reactor。
// 回调函数
typedef void (*pfn_sock_event_t)(socket_t* sock, int err, void* param);
// 非阻塞式 socket
class socket_t
{
public:
...
// 创建时,加到 socket_manager_t 管理
bool create(...)
{
...
socket_manager_t::add(this, ...);
}
// attach时,加到 socket_manager_t 管理
bool attach(SOCKET s, ...)
{
...
socket_manager_t::add(this, ...);
}
// 关闭时从 socket_manager_t 移除
void close()
{
...
socket_manager_t::remove(this, ...);
}
// 设置回调函数
void set_callback(
pfn_sock_event_t on_recv = 0,
pfn_sock_event_t on_send = 0,
pfn_sock_event_t on_accept = 0,
pfn_sock_event_t on_close = 0,
pfn_sock_event_t on_connect = 0,
pfn_sock_event_t on_except = 0
);
...
protected:
SOCKET m_sock;
pfn_sock_event_t m_on_recv,
pfn_sock_event_t m_on_send,
pfn_sock_event_t m_on_accept,
pfn_sock_event_t m_on_close,
pfn_sock_event_t m_on_connect,
pfn_sock_event_t m_on_except
...
};
// socket_manager_t
// 拥有一个 sockets 数组或列表,统一一次性进行 select()
class socket_manager_t
{
public:
...
static void add(socket_t* s, ...)
{
// 加入到 m_socks
}
static void remove(socket_t* s, ...)
{
// 从 m_socks 移除
}
// 一次性对 m_socks 中所有的 socket 进行 select()
static void poll()
{
int sck_cnt = m_socks.size();
...
for (i = 0; i < (sck - 1) / FD_SETSIZE + 1; ++i)
{
for (j = 0 ;j < FD_SETSIZE; ++j)
{
socket_t* sck = m_socks[idx];
if (...) FD_SET(sck->m_sock, fdWrite, ...);
if (...) FD_SET(sck->m_sock, fdRead, ...);
...
}
if (select(...) <= 0) continue;
for (j = 0 ;j < FD_SETSIZE; ++j)
{
socket_t* sck = m_socks[idx];
if (FD_ISSET(sck->m_sock, ...), ...)
if (sck->m_on_connect) sck->m_on_connect(sck, ...);
if (FD_ISSET(sck->m_sock, ...), ...)
if (sck->m_on_close) sck->m_on_close(sck, ...);
if (FD_ISSET(sck->m_sock, ...), ...)
if (sck->m_on_accept) sck->m_on_accept(sck, ...);
if (FD_ISSET(sck->m_sock, ...), ...)
if (sck->m_on_recv) sck->m_on_recv(sck, ...);
if (FD_ISSET(sck->m_sock, ...), ...)
if (sck->m_on_send) sck->m_on_send(sck, ...);
...
}
}
...
}
...
protected:
...
vector<socket_t*> m_socks;
};
最后,在 main() 中,或者一个独立的线程中,循环执行 socket_manager_t::poll() 如
void main()
{
...
while (!dead_event)
{
...
socket_manager_t::poll();
...
}
...
}
简单解说一下:
socket_t::create() 或者 socket_t::attach() 时登记自己到 socket_manager_t 中,由 socket_manager_t::poll()对所有的socket进行select(),触发及分派socket_t::on_recv()/socket_t::on_send()/socket_t::on_accept()等事件。
好,开始涉及ACE_Reactor。
功能上,可以等价的认为,上面的 socket_manager_t 就类似是 ACE_Rector,主要作用就是事件触发中心、事件反应器、事件监控器、事件分派器等。
就像上面的 socket 一样,各种 ACE_Event_Handler 及其派生物类,都像 socket_t::create()那样,有个向触发中心登记本身的动作,对于 ACE_Event_Handler 来说,是由程序员明显的调用 ACE_Rector 的 register(...),而 ACE_Event_Handler 本身就有 handle_input()/handle_output() 等虚拟函数,作为回调调用,就像上面的 socket_t::on_recv/socket_t::on_send... 一样。加入到 ACE_Rector 中的各种 ACE_Event_Handler,由 ACE_Rector 调用其他的事件查询/监听方式进行统一监控(比如 socket 的 select(),Win32 特有的 WSAEventSelect() 等),当有事件在 ACE_Event_Handler 上发生时,调用它的 handle_input()/handle_output()等虚拟函数。
ACE_Event_Handler 进行 ACE_Rector::register() 时,指定 READ_MASK/WRITE_MASK 等自己感兴趣的事件,handle_input()等回调被调用时返回适当的值,以指示 ACE_Rector 取消或继续监控自己。
至于 ACE_Event_Handler 还有个 handle_except() 的虚拟回调函数,跟 socket_t::on_except() 差不多。
ACE_Event_Handler 还有个 handle_timeout() 的虚拟回调,讲解一下。在我的程序中,曾经做过一个
// 回调函数
typedef void (*pfn_timer_event_t)(timer_t* tm, void* param);
class timer_t
{
...
timer_t(pfn_timer_event_t pfn, void* param, uint32 timeout_usecs)
{
m_start_tick = util_t::sys_tick();
timer_manager_t::add(this);
...
}
bool is_timeout(uint32 cur_tick)
{
return (cur_tick - m_start_tick >= m_timeout_usecs);
}
void process()
{
if (m_pfn) m_pfn(this, m_param);
}
protected;
pfn_timer_event_t m_pfn;
void* m_param;
uint32 m_start_tick;
uint32 m_timeout_usecs;
};
class timer_manager_t
{
...
void add(timer_t* tm)
{
// 加入到 m_timers
...
}
void poll()
{
uint32 cur_tick = util_t::sys_tick();
for (int i = 0; i < m_timers.size(); ++i)
{
if (m_timers[i]->is_timeout(cur_tick))
{
// 超时,触发 timer_t 的事件
m_timers[i]->process();
...
}
...
}
}
vector<timer_t> m_timers;
};
在上面的那个 main,或者一个线程中,比如
void main()
{
...
while (!dead_event)
{
...
socket_manager_t::poll();
timer_manager_t::poll();
...
}
...
}
而现在,ACE_Reactor 只不过把这个 timer_manager_t 的功能一起集成进去而已。
最后声明一下,我还没具体看 ACE 的源代码,只是暂时从 <<ACEC++NPv2>> 的讲解上,字面上根据自己的经历大概理解一下 ACE_Reactor,如果有什么错误,后期再改正。本文不打算成为什么学术指南,只作为个人经验参考。
后面的 ACE_Server_Config/ACE_Module/ACE_Task 等等,我粗览过一遍,而我的一个网络服务器程序,前期只是个login server的模块,后期因为业务需要,增加了多种server接口,以及增加了多服务器支持等,扩充维护的经历使我更能体会ACE这些动态配置、模块合作的设计安排。如果有时间,我会再结合自己的经验教训,继续写下自己的心得体会。