【问题标题】:Can I handle any received message in gen_fsm state callbacks?我可以在 gen_fsm 状态回调中处理任何收到的消息吗?
【发布时间】:2011-04-27 02:54:58
【问题描述】:

我注意到发送到 gen_fsm 进程的 pid 的消息在状态回调中作为事件匹配。这只是偶然还是我可以依赖此功能?

通常我希望发送到 gen_fsm 的一般消息会显示在 handle_info/3 回调中,并认为我必须使用 gen_fsm:send_event 重新发送它。

gen_fsm 是否首先尝试将消息与状态回调匹配,然后始终与 handle_info/3 回调匹配?还是仅当它不匹配状态回调子句时?

但是,当我尝试它时,我的消息似乎根据调试输出被处理了两次。

所以基本上这个问题也可以表述为:如何正确处理接收到的消息作为 gen_fsm 状态函数中的事件?


澄清:对于这个问题,应该考虑给出一些事件是通过传递消息而发生的。

我知道,在许多情况下,仅通过对 fsm 使用函数调用来使协议可见是一种更简洁的方法。

我不太确定这是否会改进提到的 gen_fsm 必须适应的当前框架:不同的协议栈,其中每一层调用一个 connect() 函数来附加(有时启动)较低层。数据包通过调用函数(发送)被发送到较低层,并由receive发送消息接收。很像 gen_tcp。

通过查看 gen_fsm 的代码,我已经发现一般消息仅传递给 handle_info,因此唯一的问题是直接从 handle_info/3 回调调用状态函数还是使用 gen_fsm:send_event 重新发送。

【问题讨论】:

  • 我在这里理解正确吗,您是否仅将 gen_fsm 用于某些协议栈而不是全部?如果是这样,为什么?为什么不以相同的方式实现堆栈的所有 Erlang 部分?这将使您在发送和接收消息的方式上保持一致。
  • 我一直在取消 {ok, Pid} = connect(), send(Pid, Data) 并接收 {resp, Data} 消息。所以我对栈中不同模块的API是一致的。我不一致的地方是当前对接收和发送的处理。
  • 但是有相当多的预先存在的代码使用这种范例,所以它努力改变一切。不对堆栈的所有部分使用 gen_fsm 的原因是它实际上非常多样化的协议(汽车总线协议)通过 USB 多路复用。所以堆栈的部分在 gen_server、简单的 ad/hoc 服务器和无状态编码/解码过滤器和 gen_fsm 之间当然有所不同。
  • 我接受了对整个协议栈进行更好设计的建议,并开始了一个新问题来讨论如何做到这一点的最佳方法:“如何设计灵活的 Erlang 协议栈创建API”参见“链接”部分

标签: erlang erlang-otp gen-fsm


【解决方案1】:

一般消息由 handle_info 回调处理,除非你的代码中有这样的东西:

handle_info(Info, StateName, StateData) -> ?MODULE:StateName(Info, StateData).

这避免了重新发送,但我不建议这样做,也不建议重新发送。

通过封装 send_event/sync_send_event/send_all_state_event/sync_send_all_state_event 的 API 调用专门传递事件使协议显式。这是正确的,因为使用 edoc 更容易理解、维护和记录。

【讨论】:

  • 现在的 gen_fsm 必须适应给定的协议栈架构,这些架构是按照模式构建的:低层被高层连接(),数据包被发送()但被消息接收发送到上层。类似于 gen_tcp 处理连接的方式。所以要么我改变整堆代码来传递回调而不是上游的消息,我目前宁愿不这样做,或者我必须处理这些消息。
  • 直接打电话——速度更快。此外,如果将 API 与消息传递一起使用,则重新发送时,您没有“从一个来源按顺序交付”的保证。
  • 谢谢!我已经将它实现为直接函数调用,它与其余代码非常吻合。而且它也像微风一样工作。
猜你喜欢
  • 2013-03-19
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
  • 1970-01-01
  • 2011-05-14
  • 1970-01-01
  • 2011-03-05
  • 2012-05-04
相关资源
最近更新 更多