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

7st*_*tud 0 erlang erlang-otp gen-server

当我打电话时gen_server:reply/2

gen_server:reply(From, Msg),
Run Code Online (Sandbox Code Playgroud)

客户端,From,接收具有以下格式的消息:

{Ref, Msg)
Run Code Online (Sandbox Code Playgroud)

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

receive
    {_Ref, Msg} -> Msg;
    Other -> Other
end
Run Code Online (Sandbox Code Playgroud)

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

leg*_*cia 5

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

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

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

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

在上面的代码中,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}.
Run Code Online (Sandbox Code Playgroud)

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

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}.
Run Code Online (Sandbox Code Playgroud)

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