找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 5174|回复: 4

ACE 的几个Reactor的差异问题

[复制链接]
发表于 2011-6-19 23:35:59 | 显示全部楼层 |阅读模式
背景说明:
我在开发一个跨平台的服务器,在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的问题是一致的

我查了一下原来的帖子,好像无人遇到这样的问题。
非常感谢。
 楼主| 发表于 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里,把这个通知给干掉,如果发送时发现不能发送数据了,再中途给加上去,如此反复,不知可否,先试试再说。
 楼主| 发表于 2011-6-20 00:27:40 | 显示全部楼层
试了,ok
有时间把几种reactor简单使用注意事项给总结一下
发表于 2011-6-20 14:29:17 | 显示全部楼层
发现未发送完成才注册write事件,如果send完毕再反注册,下面是我现在使用的代码,你可以参考下。
  1. int
  2. Connection_Handler::handle_output(ACE_HANDLE fd)
  3. {
  4.   ACE_Message_Block *mb = 0;
  5.   ACE_Time_Value nowait(ACE_OS::gettimeofday());
  6.   while (-1 != this->getq(mb, &nowait))
  7.   {
  8.     ssize_t send_cnt =
  9.       this->peer().send(mb->rd_ptr(), mb->length());
  10.     if (send_cnt == -1)
  11.       ACE_ERROR((LM_ERROR,
  12.                  ACE_TEXT("(%P|%t) %p\n"),
  13.                  ACE_TEXT("send")));
  14.     else
  15.       mb->rd_ptr(static_cast<size_t>(send_cnt));
  16.     if (mb->length() > 0)
  17.     {
  18.       this->ungetq(mb);
  19.       break;
  20.     }
  21.     mb->release();
  22.   }
  23.   return (this->msg_queue()->is_empty()) ? -1 : 0;
  24. }
  25. int
  26. Connection_Handler::send(ACE_Message_Block *mb)
  27. {
  28.   int empty_queue = this->msg_queue()->is_empty();
  29.   ssize_t sent = 0;
  30.   ssize_t len = mb->length();
  31.   if (empty_queue)
  32.   {
  33.     ssize_t sent =
  34.          this->peer().send(mb->rd_ptr(), len);
  35.     if (sent == len)
  36.     {
  37.       mb->release();
  38.       return 0;
  39.     }
  40.     if (sent == -1 && errno != EWOULDBLOCK)
  41.     {
  42.       mb->release();
  43.       ACE_ERROR_RETURN((LM_ERROR,
  44.                         ACE_TEXT("(%P|%t) %p\n"),
  45.                         ACE_TEXT("send")),
  46.                         -1);
  47.     }
  48.     if (sent == -1)
  49.       sent = 0;
  50.     mb->rd_ptr(sent);
  51.   }
  52.   ACE_Time_Value nowait(ACE_OS::gettimeofday());
  53.   if (this->putq(mb, &nowait) == -1)
  54.   {
  55.     ACE_ERROR((LM_ERROR,
  56.                ACE_TEXT("(%P|%t) %p\n"),
  57.                ACE_TEXT("enqueue failed")));
  58.     mb->release();
  59.     return -1;
  60.   }
  61.   if (empty_queue)
  62.     return this->reactor()->register_handler
  63.                 (this, ACE_Event_Handler::WRITE_MASK);
  64.   return 0;
  65. }
  66. int
  67. Connection_Handler::handle_close(ACE_HANDLE h , ACE_Reactor_Mask mask)
  68. {
  69.   if ( mask == ACE_Event_Handler::WRITE_MASK )
  70.     return 0;
  71.   return super::handle_close(h,mask);
  72. }
复制代码
发表于 2011-6-20 14:42:38 | 显示全部楼层
handle_output返回-1时,reactor自动移除write事件,然后调用handle_close,这时什么也别干
注意这个小技巧,另外你说的输出事件的触发时间因为底层的reactor实现不同而导致的差异(lt/et),上面的方法是可移植的,《ACE程序指南》有详细说明。希望我的描述能对你有帮助...
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-4-29 23:08 , Processed in 0.010613 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表