如何接收发送到在 gen_server 内运行的 PID 的消息
Posted
技术标签:
【中文标题】如何接收发送到在 gen_server 内运行的 PID 的消息【英文标题】:How can I receive messages sent to a PID which running inside a gen_server 【发布时间】:2021-06-02 11:39:09 【问题描述】:我有一个 ejabberd 服务器
我有一个自定义模块,my_apns_module.erl
,它由 ejabberd 服务器运行,如下所示:
start_link(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
?GEN_SERVER:start_link(local, Proc, ?MODULE,
[Host, Opts], []).
start(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
ChildSpec = Proc, ?MODULE, start_link, [Host, Opts],
temporary, 1000, worker, [?MODULE],
supervisor:start_child(ejabberd_sup, ChildSpec).
stop(Host) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
?GEN_SERVER:call(Proc, stop),
supervisor:delete_child(ejabberd_sup, Proc),
ok.
init([Host, _Opts]) ->
...
handle_call(stop, _From, State) ->
stop, normal, ok, State.
handle_cast(_Msg, State) -> noreply, State.
handle_info(#offline_msgus = _UserServer,
from = From, to = To, packet = Packet = _Msg, State) ->
...
handle_info(_Info, State) ->
noreply, State.
terminate(_Reason, State) ->
Host = State#state.host,
ok.
code_change(_OldVsn, State, _Extra) -> ok, State.
在 init 中,我运行另一个 APNs 应用程序来发送推送通知。 https://github.com/inaka/apns4erl
init([Host, _Opts]) ->
apns:start(),
case apns:connect(cert, ?APNS_CONNECTION) of
ok, PID -> ?INFO_MSG("apns connection successful with PID ~p~n", [PID]);
error, timeout -> ?ERROR_MSG("apns connection unsuccessful reason timed out", [])
end,
ok, #statehost = Host.
这是有效的,因为我可以发送通知。
现在文档 (https://github.com/inaka/apns4erl) 说:
如果网络出现故障或发生意外情况,枪 与 APN 的连接将断开。在这种情况下,apns4erl 将发送一个 向客户端进程发送消息
reconnecting, ServerPid
,这意味着 apns4erl 失去了连接,它正在尝试重新连接。一旦 连接已恢复connection_up, ServerPid
消息将 发送。
我的问题是:
我应该在my_apns_module.erl
中写什么代码来接收reconnecting, ServerPid
或connection_up, ServerPid
?
【问题讨论】:
【参考方案1】:发送到 gen_server 进程的消息,例如GenServerPid ! ok, 10
,由:
handle_info(Msg, State)
所以,你可以这样做:
handle_info(reconnecting, ServerPid=Msg, State) ->
%%do something here, like log Msg or change State;
handl_info(connection_up, ServerPid=Msg, State) ->
%%do something here, like log Msg or change State;
handle_info(#offline_msgus = _UserServer,
from = From, to = To, packet = Packet = _Msg, State) ->
%%do something.
对评论的回应:
这是您当前的代码:
init([Host, _Opts]) ->
apns:start(),
case apns:connect(cert, ?APNS_CONNECTION) of
ok, PID -> ?INFO_MSG("apns connection successful with PID ~p~n", [PID]);
error, timeout -> ?ERROR_MSG("apns connection unsuccessful reason timed out", [])
end,
ok, #statehost = Host.
你可以把它改成这样:
init([Host, _Opts]) ->
spawn(?MODULE, start_apns, []),
...
start_apns() ->
apns:start(),
case apns:connect(cert, ?APNS_CONNECTION) of
ok, PID -> ?INFO_MSG("apns connection successful with PID ~p~n", [PID]);
error, timeout -> ?ERROR_MSG("apns connection unsuccessful reason timed out", [])
end,
apns_loop().
apns_loop() ->
receive
reconnecting, ServerPid -> %%do something;
connection_up, ServerPid -> %% do something;
Other -> %% do something
end,
apns_loop().
启动apns进程后,apns进程会进入循环等待消息。
【讨论】:
等一下...消息不会发送到 gen_server,比如说 GenServerPID,而是发送到在 gen_server 中运行的进程,比如说 PID。该过程由语句 OK, PID = apns:connect(cert, ?APNS_CONNECTION) 启动。所以 GenServerPID 是由 ejabberd 启动的,而 PID 是通过 my_apns_module 中的 apns:connect 启动的。据我了解,handle_info 将处理 ejabberd 服务器发送到 GenServerPID 的消息。它还会处理发送到 PID 的消息吗? 据我所知,handle_info 将处理 ejabberd 服务器发送到 GenServerPID 的消息。它还会处理发送到 PID 的消息吗?-- 发送到非 gen_server 进程的消息需要由接收子句处理。 @GJain,我添加了一个你可以做什么的例子。 对不起......我还有一个问题...... PID)还是(是 spawnPID == PID)? GJain,哪个进程是PID? 在这种情况下,apns4erl 将向客户端进程发送一条消息 reconnecting, ServerPid -- 你必须弄清楚哪个进程是client process
。以上是关于如何接收发送到在 gen_server 内运行的 PID 的消息的主要内容,如果未能解决你的问题,请参考以下文章
如何在 erlang gen_server 中有效地使用接收子句来解决超时错误?