我可以在 gen_fsm 状态回调中处理任何收到的消息吗?
Posted
技术标签:
【中文标题】我可以在 gen_fsm 状态回调中处理任何收到的消息吗?【英文标题】:Can I handle any received message in gen_fsm state callbacks? 【发布时间】: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”参见“链接”部分 【参考方案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 与消息传递一起使用,则重新发送时,您没有“从一个来源按顺序交付”的保证。 谢谢!我已经将它实现为直接函数调用,它与其余代码非常吻合。而且它也像微风一样工作。以上是关于我可以在 gen_fsm 状态回调中处理任何收到的消息吗?的主要内容,如果未能解决你的问题,请参考以下文章
发送消息时确保 gen_fsm/gen_server 进程存在
在这种情况下我应该使用哪种 Erlang 行为,即 gen_server 或 gen_fsm
我收到此错误:“来自 useState() 和 useReducer() Hooks 的状态更新不支持第二个回调...”当我更改状态时