sunlock 发表于 2011-6-19 23:35:59

ACE 的几个Reactor的差异问题

背景说明:
我在开发一个跨平台的服务器,在windows上用的proactor,服务器目前运行还可以。现在我要在linux上(redhat)上提供我的服务器。前面发现在linux上使用proactor根本不能正常工作,好在我的服务器当时设计时考虑考虑了使用不同模型。
现在打算在linux上使用reactor,但不管是用何种reactor的实现,如select,tp,还是dev_poll,都有问题,于是我就用tp_reactor在windows上试了一下,发现有同样的问题:我在ACE_Svc_Handler的子类(或者你也可以说是Event_handler的子子类)的Open函数中注册了2种通知readmask和writeMask,运行时总是不停的调用handle_output,而handle_input 从不被调用,如果我在open里面只注册readmask,则handle_input可以正常被调用,但是我的程序原来设计时是需要handle_output去触发一个条件的,这样就没法工作了。
同样的情况,我在windows下使用wfmo_reactor,在open里面注册2种通知,工作毫无问题。
难度是select_reactor ,或 tp_reactor在使用时有些不同之处吗(我现在暂时不管dev_poll了)?
目前的表现是windows和linux的问题是一致的

我查了一下原来的帖子,好像无人遇到这样的问题。
非常感谢。

sunlock 发表于 2011-6-20 00:12:23

本帖最后由 sunlock 于 2011-6-20 00:16 编辑

另外,我用卷2中 tp_reactor_logserver的例子改了一下(做个验证),同时注册两个通知:readmask和writemask,然后用卷1例子的客户端连接一下,出现的问题跟我的一致。也就是handle_input根本不会被触发,而handle_output不停的被触发。

同样我使用的是线程池,也就是预备了足够的线程。

我怀疑tp或select reactor在网络处理器上一般不注册write通知。select一检测到可发送就触发了handle_output ,这样内部可能老检测到同一个事件并处理这个事件,不管后面有多少个在等待或等待了多长时间

我突然想到一个办法,一开始时注册write,等第一次触发handle_output里,把这个通知给干掉,如果发送时发现不能发送数据了,再中途给加上去,如此反复,不知可否,先试试再说。

sunlock 发表于 2011-6-20 00:27:40

试了,ok
有时间把几种reactor简单使用注意事项给总结一下

wesom 发表于 2011-6-20 14:29:17

发现未发送完成才注册write事件,如果send完毕再反注册,下面是我现在使用的代码,你可以参考下。int
Connection_Handler::handle_output(ACE_HANDLE fd)
{
ACE_Message_Block *mb = 0;
ACE_Time_Value nowait(ACE_OS::gettimeofday());
while (-1 != this->getq(mb, &nowait))
{
    ssize_t send_cnt =
      this->peer().send(mb->rd_ptr(), mb->length());
    if (send_cnt == -1)
      ACE_ERROR((LM_ERROR,
               ACE_TEXT("(%P|%t) %p\n"),
               ACE_TEXT("send")));
    else
      mb->rd_ptr(static_cast<size_t>(send_cnt));
    if (mb->length() > 0)
    {
      this->ungetq(mb);
      break;
    }
    mb->release();
}
return (this->msg_queue()->is_empty()) ? -1 : 0;
}

int
Connection_Handler::send(ACE_Message_Block *mb)
{
int empty_queue = this->msg_queue()->is_empty();
ssize_t sent = 0;
ssize_t len = mb->length();
if (empty_queue)
{
    ssize_t sent =
         this->peer().send(mb->rd_ptr(), len);
    if (sent == len)
    {
      mb->release();
      return 0;
    }
    if (sent == -1 && errno != EWOULDBLOCK)
    {
      mb->release();
      ACE_ERROR_RETURN((LM_ERROR,
                        ACE_TEXT("(%P|%t) %p\n"),
                        ACE_TEXT("send")),
                        -1);
    }
    if (sent == -1)
      sent = 0;
    mb->rd_ptr(sent);
}
ACE_Time_Value nowait(ACE_OS::gettimeofday());
if (this->putq(mb, &nowait) == -1)
{
    ACE_ERROR((LM_ERROR,
               ACE_TEXT("(%P|%t) %p\n"),
               ACE_TEXT("enqueue failed")));
    mb->release();
    return -1;
}
if (empty_queue)
    return this->reactor()->register_handler
                (this, ACE_Event_Handler::WRITE_MASK);
return 0;
}

int
Connection_Handler::handle_close(ACE_HANDLE h , ACE_Reactor_Mask mask)
{
if ( mask == ACE_Event_Handler::WRITE_MASK )
    return 0;
return super::handle_close(h,mask);
}

wesom 发表于 2011-6-20 14:42:38

handle_output返回-1时,reactor自动移除write事件,然后调用handle_close,这时什么也别干
注意这个小技巧,另外你说的输出事件的触发时间因为底层的reactor实现不同而导致的差异(lt/et),上面的方法是可移植的,《ACE程序指南》有详细说明。希望我的描述能对你有帮助...
页: [1]
查看完整版本: ACE 的几个Reactor的差异问题