关于otp:在erlang中难以采用gen_server体系结构

 2021-04-26 

Difficulty adopting gen_server architecture in erlang

我对erlang比较陌生,并编写了以下模块:

1
2
3
4
5
6
7
8
-module(gserver).
-export([start1/0]).
-define(SERVER, gserver).

 start1() ->
 serv_util:start(?SERVER,
                  { gserver, game_loop,
                    [dict:new(), dict:new()]}).

serv_util:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-module(serv_util).
-export([start/2]).

 start(ServerName, {Module, Function, Args}) ->
 global:trans({ServerName, ServerName},
            fun() ->
                case global:whereis_name(ServerName) of
                    undefined ->        
                        Pid = spawn(Module, Function, Args),
                        global:register_name(ServerName, Pid);
                _ ->
                    ok
                end
            end).

然后我尝试将其置于erlang的gen_server体系结构下,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
-module(s_child).
-behaviour(gen_server).

 -export([start/0,stop/0]).
 -export([init/1, handle_call/3,handle_cast/2, terminate/2,
  handle_info/2,code_change/3]).


 -import(gserver,[start1/0]).
 -import(gclient,[login/1]).



  start()->
  gserver:start1(),
  gen_server:start_link({global,?MODULE}, ?MODULE, [], []).

   stop()->
   gen_server:cast(?MODULE, {stop}).

  log_in(Name)->
  gen_server:call({global,?MODULE}, {login,Name,self()}).

  init(_Args) ->
   io:format("Hello started ~n"),
   {ok,_Args}.

   handle_call({login,Name},_From,State)->
   State,
   Reply=login(Name),
   {reply, Reply,State}.

但是当我按以下顺序调用时

1)s_sup:start_link()。

你好,开始了
{ok,<0.344.0>}

2)s_child:log_in(" Abhishek ")。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
** exception exit: {{function_clause,
                        [{s_child,handle_call,
                             [{login,"Abhishek",<0.335.0>},
                              {<0.335.0>,#Ref<0.0.4.457>},
                              []],
                             [{file,"s_child.erl"},{line,61}]},
                         {gen_server,try_handle_call,4,
                             [{file,"gen_server.erl"},{line,615}]},
                         {gen_server,handle_msg,5,
                             [{file,"gen_server.erl"},{line,647}]},
                         {proc_lib,init_p_do_apply,3,
                             [{file,"proc_lib.erl"},{line,247}]}]},
                    {gen_server,call,
                        [{global,s_child},{login,"Abhishek",<0.335.0>}]}}
     in function  gen_server:call/2 (gen_server.erl, line 204)

我无法理解代码中第61行到底是什么错误。在第61行的完整代码中,存在以下代码:

1
2
3
handle_call(stop,  _From, State) ->

{stop, normal, ok, State};

即第一个handle_call在第61行出现

有人可以在这里帮我吗?


log_in函数中,将{login,Name,self()}作为gen_server调用传递,但是handle_call函数仅需要{login,Name}。因此,由于没有匹配子句,因此对handle_call的调用失败。

您不需要传递self(),因为您可以使用reply功能来确保响应将其返回给调用方,因此只需修改log_in即可将{login,Name}传递给gen_server:call


Legoscia的答案是正确的。
我建议参阅了解gen_server。
本文提供了有关使用gen_server的有用信息。