Erlang Gen_Server Architecture Issues

I am in the early stages of Erlang training and I need more help. Not sure if it will get sunlight, but here it is ... I'm looking for a flow diagram, how the example works.

Example code: https://github.com/erlware/Erlang-and-OTP-in-Action-Source/blob/master/chapter_03/tr_server.erl

Let me explain my problem ...

1> tr_server:start_link().

I understand this, it calls start_link (? DEFAULT_PORT), which calls gen_server: start_link - and this actually returns the call to init_rserver (? MODULE) init ([Port]).

init([Port]) ->
    {ok, LSock} = gen_tcp:listen(Port, [{active, true}]),
    {ok, #state{port = Port, lsock = LSock}, 0}.

This is also understandable. You send data to the server, gen_server: handle_info / 2 is processed and, therefore, calls ,? MODULE: handle_info / 2 is the case, and since we returned the timeout to? MODULE: init, in this case will correspond to handle_info (timeout, #state {lsock = LSock} = State).

Ok, that makes sense.

Here I start to get confused in the Erlang thread

For several days I read online resources about this (including Erlang-and-OTP-in-action), where this example comes from, also: http://learnyousomeerlang.com/clients-and-servers

, Erlang. , , , gen_server: handle_info/2, - , gen_server: handle_call/3? , TCP gen_server: handle_info/2 - : MODULE: handle_info?

, , - , handle_call, handle_cast - NOR - ( , ). , , , .

: , :

lists:reverse([1,2,3]).

-, , . , . , :

get_count() ->
    gen_server:call(?SERVER, get_count).

stop() ->
    gen_server:cast(?SERVER, stop).

, , ! !

+4
2

, , tcp, , handle_info. /, Erlang , . Erlang / Erlang, Erlang. ( gen_server Erlang.)

gen_server: call/cast client, , , gen_server , handle_call/handle_cast. , , tcp: , . gen_server: call() ( Pid ), gen_server: cast() .

. , gen_server , , , , . , , , , /. : โ†’ โ†’ [- > โ†’ ].

, get_count() ?SERVER ! {get_count, self()}, handle_info(), handle_call(). ( Pid, โ€‹โ€‹ , .)

API-, get_count(), {get_count, self()} ( ). , . gen_server: call/cast , /.

, .

+8

Erlang, .

  • , gen_server -. - .
  • .
  • gen_server .
  • gen_server. .
  • gen_tcp .
  • , gen_tcp gen_server.

:

http://erlang.org/doc/design_principles/des_princ.html

6, , , .

, TCP gen_server: handle_info/2 - ? : handle_info

. TCP gen_server. TCP , , . , gen_server: handle_info() . handle_info() , , handle_info().

, TCP, handle_info(). , handle_info(), :

handle_info({tcp, Socket, RawData}, State) ->
    Result1 = computerInGermanyProcess(RawData),
    Result2 = computerInFranceProcess(RawData),
    Result3 = computerInRussiaProcess(RawData),    
    Result4 = State#state.stored_val,

    gen_tcp:send(Socket, [Result1, Result2, Result3, Result4]),
    {noreply, State};  %%Because a TCP message landed in the mailbox with no From value, 
                       %%do not reply to From, and do not mess with the value in State.

 computerInGermanyProcess(RawData) ->
          %% Possibly use gen_tcp and sockets again to send a message
          %% to another computer to get some data in order to
          %% calculate Result1:
          Result1.
 computerInFranceProcess(RawData) ->
          ...
          Result2.
 computerInRussiaProcess(RawData) ->
          ...
          Result3.         

, , handle_call, handle_cast play - NOR - ( , ). , .

Client:                                                                    
+------------------------------------------------------+------------------------------------------------------+
| my_request() ->                                      |   handle_call({dostuff, Val}, ClientPid, State) ->   |
|     Request = {dostuff, 10},                         |       %%Do something with Val, State                 |
|     Server = ?MODULE,                                |       Response = {result, 45},                       |
|     Response = gen_server:call(Server, Request).     |       NewState = ....,                               |
|                            |                         |       {Response, NewState}.                          |
|                            |       from gen_server:  |                                                      |
|                            |            start_link() |                                     ^                |
|                            |                 |       |                                     |                |
+----------------------------+-----------------+-------+-------------------------------------+----------------+
                             |                 |                                             |
                             |                 |                                             |
+----------------------------+-----------------+-------+                                     |
|-module(gen_server).        |                 |       |                                     |
|-export([call/2,....]).     V                 |       |                                     |
|                                              |       |                                     |
|call(Server, Request) ->                      V       |                                     |
|  Server ! {request, Request, call, self(), Module} --+-->+                                 |                     
|  receive                                             |   |                                 ^                
|      {reply, Response, Server} ->                    |   |                                 |
|          Response      ^                             |   V                                 |
|  end.                  |                             |   |                                 |
+------------------------+-----------------------------+   |                                 |
|   Mailbox              |                             |   |                                 |
|                        |                             |   |                                 |
|       {reply, Response, Server}  <----------<--------+---+--------------<--------------+   |
|                                                      |   V                             ^   ^      
+------------------------------------------------------+   |                             |   |
                                                           |                             |   |
                                                           |                             |   |
Server:                                                    |                             |   |
+------------------------------------------------------+   |                             |   |
|    Mailbox                                           |   |                             |   |
|                                                      |   V                             ^   ^
|        {request, Request, call, ClientPid, Module} <-+---+                             |   |
|                            |                         |                                 |   |
+----------------------------+-------------------------+-----------------------------+   |   |                 
|                            |                                                       |   |   |
|loop(State) ->              |                                                       |   |   |
|    receive                 V                                                       |   ^   ^
|        {request, Request, call, ClientPid, Module}  ->                             |   |   |           ^
|            {Response, NewState} = Module:handle_call(Request, ClientPid, State} ---+---|-->+           |
|            ClientPid ! {reply, Response, self()}, ----------->---------------------+-->+            To Client
|            loop(NewState);                                                         |                   ^
|        {request, Request, cast, ClientPid, Module} ->                              |                   |
|            NewState = Module:handle_cast(Request, State), ------->---------->------|----->------------>+
|            loop(NewState);                                                         |
|        ...                                                                         |
|        ...                                                                         |                                      
|    end.                                                                            |
+------------------------------------------------------------------------------------+

, gen_server:call():

  • gen_server:start_link(), , , , handle_call/handle_cast.

  • gen_server:call(ServerName, Request), .

  • gen_server: (_, ) send a message to the server, :

     ServerName ! {request, Request, call, self(), ModName}.
    

    , gen_server: start_link(): - , , handle_call(), handle_cast() ..

  • , ModName:handle_call(), ModName: handle_call() - :

    handle_call(Request, ClientPid, ServerLoopValue) ->
        %%Compute some result using information in Request/ServerLoopValue
    
  • ModName: handle_call() , a response:

      {Response, NewServerLoopValue}.
    

    - :

      From ! {reply, Response, ServerPid}.
      loop(NewServerLoopValue).
    

    NewServerLoopValue (). loop(), :

    loop(ServerLoopValue) ->
        receive
            {request, dothis, From} ->
                Result1 = ...SomeValue + 5....,
                From ! {Result1, self()},
                loop(NewServerLoopValue);
            {request, {dothat, 10}, From} ->
                Result2 = ... SomeValue - 10...,
                From ! {Result2, self()},
                loop(NewServerLoopValue);
            {request, stop, From}
                %%do not call loop()
        end.
    

    ServerLoopValue , . gen_server , ServerLoopValue, ServerLoopValue, .

, gen_server TCP- {active, true}, {packet, 4}:

  • gen_tcp:send().

  • Erlang , server mailbox.

  • {tcp,...} handle_info().

  • handle_info() gen_tcp:send(Socket, Response), .

  • handle_info() , loop() :

    {noreply, SomeValue}   =>  loop(SomeValue)
    

, gen_server TCP- {active, false}, {packet, 0}:

Erlang gen_tcp

+2

Source: https://habr.com/ru/post/1677179/


All Articles