Могу ли я обрабатывать любое полученное сообщение в обратных вызовах состояния gen_fsm?

Я заметил, что сообщения, отправленные в pid процесса gen_fsm, сопоставляются в обратных вызовах состояния как события. Это случайно или я могу положиться на эту функцию?

Обычно я ожидал, что общие сообщения, отправленные в 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.


person Peer Stritzinger    schedule 18.10.2010    source источник
comment
Правильно ли я вас понял, вы используете gen_fsm только для части стека протоколов, а не для всего? Если да, то почему? Почему бы не реализовать всю Erlang-часть стека одинаково? Это позволит вам быть последовательным в том, как сообщения отправляются и принимаются.   -  person rvirding    schedule 19.10.2010
comment
Я последовательно отключаю сообщения {ok, Pid} = connect(), send(Pid, Data) и получаю сообщения {resp, Data}. Так что я последователен в API разных модулей в стеке. Где я не последовательна, так это в обработке получения и отправки в настоящее время.   -  person Peer Stritzinger    schedule 20.10.2010
comment
Но существует довольно много уже существующего кода, использующего эту парадигму, так что это попытка изменить все заново. Причина, по которой gen_fsm не используется для всех частей стека, заключается в том, что на самом деле его очень разные протоколы (протоколы автомобильных шин) мультиплексируются через usb. Таким образом, части стека различаются между gen_server, простым специальным сервером и фильтрами кодирования/декодирования без сохранения состояния и, конечно же, gen_fsm.   -  person Peer Stritzinger    schedule 20.10.2010
comment
Я принял предложение по улучшению дизайна всего стека протоколов и задал новый вопрос, чтобы обсудить, как лучше всего это сделать: Как разработать гибкий API для создания стека протоколов Erlang. См. Связанный раздел.   -  person Peer Stritzinger    schedule 30.10.2010


Ответы (1)


Общие сообщения обрабатываются обратным вызовом handle_info, если в вашем коде нет чего-то подобного:

handle_info(информация, StateName, StateData) -> ?MODULE:StateName(Info, StateData).

Что позволяет избежать повторной отправки, но я не рекомендую ни этого, ни повторной отправки.

Доставка событий исключительно с помощью вызовов API, инкапсулирующих send_event/sync_send_event/send_all_state_event/sync_send_all_state_event, делает протокол явным. И это правильно, так как его легче понять, поддерживать и документировать с помощью edoc.

person probsolver    schedule 18.10.2010
comment
На данный момент gen_fsm должен вписываться в заданную архитектуру стеков протоколов, построенных по шаблону: нижние уровни соединяются() с более высокими уровнями, пакеты отправляются(), но принимаются посредством отправки сообщений на более высокие уровни. Аналогично тому, как gen_tcp обрабатывает соединения. Поэтому либо я изменяю всю кучу кода, чтобы передавать обратные вызовы вместо сообщений для восходящего потока, чего я скорее не делаю в настоящее время, либо мне приходится обрабатывать эти сообщения. - person Peer Stritzinger; 18.10.2010
comment
Звоните напрямую - так быстрее. Кроме того, в случае повторной отправки, если используется API вместе с передачей сообщения, у вас нет гарантии последовательной доставки из одного источника. - person probsolver; 19.10.2010
comment
Спасибо! Я уже реализовал его как прямой вызов функции, и он хорошо сочетается с остальным кодом. И это работает как ветер также. - person Peer Stritzinger; 20.10.2010