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:16 编辑
另外,我用卷2中 tp_reactor_logserver的例子改了一下(做个验证),同时注册两个通知:readmask和writemask,然后用卷1例子的客户端连接一下,出现的问题跟我的一致。也就是handle_input根本不会被触发,而handle_output不停的被触发。
同样我使用的是线程池,也就是预备了足够的线程。
我怀疑tp或select reactor在网络处理器上一般不注册write通知。select一检测到可发送就触发了handle_output ,这样内部可能老检测到同一个事件并处理这个事件,不管后面有多少个在等待或等待了多长时间
我突然想到一个办法,一开始时注册write,等第一次触发handle_output里,把这个通知给干掉,如果发送时发现不能发送数据了,再中途给加上去,如此反复,不知可否,先试试再说。 试了,ok
有时间把几种reactor简单使用注意事项给总结一下 发现未发送完成才注册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);
} handle_output返回-1时,reactor自动移除write事件,然后调用handle_close,这时什么也别干
注意这个小技巧,另外你说的输出事件的触发时间因为底层的reactor实现不同而导致的差异(lt/et),上面的方法是可移植的,《ACE程序指南》有详细说明。希望我的描述能对你有帮助...
页:
[1]