瑞克 发表于 2009-7-14 10:26:08

资料匮乏,有2个问题不解,恳请各位高手解答

我手头只有C++网络编程卷1,卷2和一本ACE程序员教程,但是感觉内容很不全,在网上看一些例子要连看带猜,但是这个例子我始终猜不通了,只好求助大家。
程序地址如下:
http://blog.csdn.net/jacklam200/archive/2008/12/08/3478375.aspx

关于这个例子,我有2处不明白。
首先是服务器端:
int ClientService:: open(void *p)
{
    if(ACE_Svc_Handler:: open(p)==-1)
      return -1;
    ACE_TCHAR peer_name;
    .......
    return 0;
}
ACE_Svc_Handler:: open(p)这个函数的功能仅仅向反应器注册自身,掩码是ACE_EVENT_HANDLE::READ_MASK,那么,下面的int ClientService::handle_output(ACE_HANDLE) 方法为什么会被回调呢? 并没有找到地方注册掩码ACE_EVENT_HANDLE::WRITE_MASK啊。 这是我不明白的地方之一。

其次,下面那段客户端的代码,我不明白的地方是this->msg_queue()->notification_strategy(this->notifier_),和随后的
if(this->msg_queue()->is_empty())
      this->reactor()->cancel_wakeup(this,ACE_Event_Handler::WRITE_MASK);
    else
      this->reactor()->schedule_wakeup(this,ACE_Event_Handler::WRITE_MASK);
    return 0;

解释上说: "对于我们想要发往服务器的每一个串,我们都把它插入一个ACE_Message_Block,并把这个块放入队列,这将使消息队列用notifier_对象把通知放入反应器的队列。当反应器处理该通知时,他会调用我们的handle_output方法,然后我们从队列中取出数据,直到队列变空。"

我是这么理解这个流程的:首先消息入队,会调用一次handler_output,然后如果在一次调用中没有没处理完全部的消息块,就设置ACE_Event_Handler::WRITE_MASK,迫使反应器再度回调handler_output方法,直至消息处理完毕,去除WRITE_MASK掩码,handler_output不再被调用,等到下次再有数据入队,继续调用一次handler_output方法,然后循环以上流程,反复。

不知道我的理解对不对,我手头资料很匮乏,只好连看带猜,这是我唯一推导出貌似合理的结论了,很不容易发现这个论坛,请各位高手解惑我这两个小问题。多谢了。

modern 发表于 2009-7-14 13:33:42

我提供两点建议:
1.你手里的三本书,完全可以满足你对ACE的日常需求了,大家都是这么过来的。
下面这个帖子或许对你会有帮助。
http://www.acejoy.com/bbs/viewthread.php?tid=1260&extra=page%3D1
2.ACE已经提供了例子的源代码,而且书上都说明的使用方法,
楼主您却反其道而行之,这样会平白多走很多弯路的!

[ 本帖最后由 modern 于 2009-7-15 17:17 编辑 ]

瑞克 发表于 2009-7-15 11:22:26

我是在工程中看到了对ACE_Svc_Handler的open调用才有疑惑的。要知道,我在ACE程序员指南中从来没有看到过这种用法,后来刨根问底才查到了默认open的定义,之后想不通为什么会调用handler_output,于是有了问题之一。

至于问题二,我这3本书上也没有提到策略模式和策略模式应用于message_queue中的方法,所以我是按照书面的意思去推测理解背后发生的事情。

我并非企图按照这个例子去搭建一个网络服务器,而且我们的服务器也完全不是这么搞的,但是我在搜寻的过程中,无意中发现了这个例子有和我们服务器相符合的东西。本质上,我是想弄清楚问题一,问题二背后涉及到的东西。

modern 发表于 2009-7-15 13:01:56

第一个问题可以参考C++NPV2
WRITE_MASK semantics different from select(). When a socket can send more data, select() detects a WRITE condition. It will continue to detect this condition as long as the socket remains writeable, that is, until it becomes flow controlled. In contrast, the Windows WSAEventSelect() function only sets the WRITE event when the socket is first connected, whether passively or actively, and when the socket transitions from flow-controlled to writeable. When relying on WRITE events using the ACE_WFMO_Reactor, you must therefore continue to write until the connection closes or the socket becomes flow controlled and a send() fails with EWOULDBLOCK. If this behavior is undesirable, you might consider choosing the ACE_Select_Reactor as the ACE_Reactor implementation on Windows since it has the same WRITE_MASK semantics as on UNIX platforms.
第二个问题,楼主所谓的策略模式是什么?notification_strategy?
如果是这个的话,可以参考C++NPV2的第3,4章,也可以参考下面的帖子。
http://www.acejoy.com/bbs/viewthread.php?tid=964&extra=page%3D1。
我个人也比较赞同帖子的部分观点,这个通知机制中包含了不少小陷阱,
想用对通知机制恐怕得需要花费楼主你不少时间,
如果仅在windows下开发的,有很多替代的办法,不建议使用通知机制。

Joe 发表于 2009-7-15 13:55:24

1.为什么会调用handler_output?
ACE_Event_Handler::WRITE_MASK是在handle_input里注册的.
2.参考APG :p137-p140

瑞克 发表于 2009-7-15 16:40:33

感谢各位沙发,地板,地面的帮助,让我在黑暗中少了很多摸索。
貌似我对策略模式的推测还是正确的。

modern 发表于 2009-7-15 17:16:48

抱歉,开始的时候看代码不是很认真,
多谢5楼的提示,我刚看了一遍你说的位置。
这是一个非常棒的演示Reactor通知策略使用的例子。

至于handler_output为什么会被调用,关键的是下面这段代码。
Client():notifier_(0,this,ACE_Event_Handler::WRITE_MASK)
    {
    }

首先,由定时器生成带发送数据,然后通过this->putq(mb); 插入消息队列。
由于设置了通知策略,因此插入消息队列的过程中,会将这段报文包装成一个通知,
handler是this指针,mask是ACE_Event_Handler::WRITE_MASK,看到前面的构造函数了么?
最后,Reactor的会将该通知分发,由于是mask被设置为ACE_Event_Handler::WRITE_MASK,
因此handler_output会被调用。

[ 本帖最后由 modern 于 2009-7-15 17:26 编辑 ]
页: [1]
查看完整版本: 资料匮乏,有2个问题不解,恳请各位高手解答