gen_server:reply / 2:发送给客户端的消息格式

时间:2019-06-24 17:25:45

标签: erlang otp gen-server

当我致电gen_server:reply/2时:

gen_server:reply(From, Msg),

客户端From收到以下格式的消息:

{Ref, Msg)

我找不到关于gen_server:reply/2发送的消息格式的任何文档,我想知道如何在消息中对Ref进行模式匹配。目前,我为Ref使用了一个无关变量:

receive
    {_Ref, Msg} -> Msg;
    Other -> Other
end

这意味着除gen_server以外的其他进程可能会向我的客户发送与{_Ref, Msg}子句匹配的消息。

2 个答案:

答案 0 :(得分:3)

在调用gen_server:reply(From, Msg)中,From不仅是客户端:它实际上是一个元组,包含两个值,即调用方的进程ID和唯一引用。我们可以在the implementation of gen_server:reply/2中看到它:

%% -----------------------------------------------------------------
%% Send a reply to the client.
%% -----------------------------------------------------------------
reply({To, Tag}, Reply) ->
    catch To ! {Tag, Reply}.

这个想法是Tag是呼叫者提供的唯一值,因此呼叫者可以将呼叫的结果与任何其他传入消息区分开:

Ref = make_ref(),
MyServer ! {'$gen_call', {self(), Ref}, foo},
receive
    {Ref, Reply} -> io:format("Result of foo call: ~p~n", [Reply])
end

在上面的代码中,receive将阻塞,直到获得对此调用的响应为止。

({gen_server:call/2会执行上述操作,并另外监视服务器以防崩溃,并检查超时。)

未记录此文件的原因是,它被认为是内部实现细节,可能会发生更改,建议用户依靠gen_server:callgen_server:reply而不是自己生成和匹配消息。


大多数时候您根本不需要使用gen_server:reply/2:服务器进程接收到一个调用并进行同步处理,返回一个reply元组:

handle_call(foo, _From, State) ->
    %% ignoring 'From' here, because we're replying immediately
    {reply, foo_result, State}.

但是有时您希望服务器进程延迟回复呼叫,例如等待网络输入:

handle_call(foo, From, State) ->
    send_request(foo),
    NewState = State#state{pending_request = From},
    {noreply, NewState}.

handle_info({received_response, Response}, State = #state{pending_request = From}) ->
    gen_server:reply(From, Response),
    NewState = State#state{pending_request = undefined},
    {noreply, NewState}.

在上面的示例中,我们将From值保存在服务器状态下,并且当响应以Erlang消息的形式出现时,我们将其转发给调用方,该调用方将阻塞直到获得响应。 (一个更现实的示例将同时处理多个请求,并以某种方式将传入的响应与未完成的请求进行匹配。)

答案 1 :(得分:1)

它是gen_ *行为所使用的gen.erl功能。您可以看到gen_event's callgen_server's callgen_statem's call
那怎么运作的呢?
这个想法很简单,当您调用gen:call/4gen:call(Process, Label, Request, Timeout)时,它将监视Process。因此erlang:monitor/2产生参考。它使用此引用并将消息以Process的形式发送到{Label, {self(), Ref}, Request}。之后,它会等待{Ref, Reply}中指定的Timeout,并在收到回复后将其作为恶魔Process。同样,如果Process在发送Reply时崩溃,或者即使Process在调用前是死pid,它也会收到{'DOWN', Ref, _, _, Reason}

例如,gen_server:call/2-3呼叫gen:call(Prpcess, '$gen_call', Req, Timeout)。当服务器Process(是gen_server)接收到它时,它假定这是一个调用请求,因此调用了handle_call函数,等等。