Warning: strpos() [function.strpos]: Empty needle in /home/dealer/kasat/pkg/cahir/web/html/lib/plugins/translation2/action.php on line 53

Warning: Cannot modify header information - headers already sent by (output started at /home/dealer/kasat/pkg/cahir/web/html/lib/plugins/translation2/action.php:53) in /home/dealer/kasat/pkg/cahir/web/html/inc/actions.php on line 163
erlang:otp-server [Krystian Bacławski Wiki]
 

Szablon serwera

Opis działania

Szablon serwera jest najprostszym z dostępnych w OTP.

Funkcjonalność serwera sprowadza się do obsługi zdarzeń:

  • synchronicznych - w ich przypadku serwer musi odesłać odpowiedź,
  • asynchronicznych.

Serwer posiada swój stan wewnętrzny, który jest modyfikowany w wyniku w obsługi zdarzeń, minięcia limitu czasowego lub innych komunikatów.

Część uniwersalna

Startowanie procesu

gen_server:start(Module, Args, Options) -> Result
gen_server:start(ServerName, Module, Args, Options) -> Result
 
gen_server:start_link(Module, Args, Options) -> Result
gen_server:start_link(ServerName, Module, Args, Options) -> Result

Serwer zostaje zarejestrowany:

  • lokalnie jeśli ServerName = {local,Name},
  • globalnie jeśli ServerName = {global,Name}.

Argument Options składa się z listy krotek:

  • {debug,DebugOpts} - domyślne flagi odpluskwiania
  • {timeout,Time} - czas oczekiwania na zakończenie inicjalizacji procesu,
  • {spawn_opt,SpawnOpts} - opcje startowania procesu (patrz funkcja erlang:spawn_opts).

Powyższe funkcje zwracają:

  • {ok,Pid} - inicjalizacja procesu zakończyłą się powodzeniem,
  • ignore - Module:init/1 zwróciło ignore,
  • {error,timeout} - inicjalizacja procesu trwała zbyt długo, więc został zabity,
  • {error,{already_started,Pid}} - proces z podaną nazwą został już wystartowany i posiada indentyfikator Pid,
  • {error,Error} - jeśli inicjalizacja zakończyła się błędem lub Module:init/1 zwróciło {stop,Reason}.

Wywołania

Przy komunikacji z procesami potrzebne są nam uchwyty. Uchwyt do procesu (ProcRef) może być wyrażony na następujące sposoby:

  • Name - zarejestrowany lokalny,
  • {Name,Node} - zarejestrowany na węźle,
  • {global,GlobalName} - zarejestrowany globalnie,
  • Pid - identyfikator procesu.

Synchroniczne

gen_server:call(ProcRef, Request, Timeout) -> Reply

Wysyła komunikat Request do procesu identyfikowanego przez ServerRef. Parametr Timeout jest opcjonalny - jeśli odpowiedź nie nadejdzie w odpowiednim czasie, funkcja rzuci wyjątek. Uwaga: powyższa funkcja nie zabezpiecza przed przyjściem odpowiedzi po upłynięciu limitu czasowego.

gen_server:multi_call(Nodes, Name, Request, Timeout) -> Result

gdzie wynik jest zdefiowany następująco:

{[{Node,Reply}],BadNodes}

Zakłada, że na wskazanej liście węzłów istnieją zarejestrowane lokalnie procesy o nazwie Name. Parametr Timeout jest opcjonalny. Do wysłania żądań używane są procesy pośredniczące. Wynik składa się z listy odpowiedzi {Node,Reply} i listy węzłów, które nie istnieją lub nie posiadają zarejestrowanego procesu o nazwie Name.

Asynchroniczne

gen_server:cast(ProcRef, Request)

Funkcja wysyła komunikat do podanego procesu. Funkcja zawsze zwraca atom ok - nawet jeśli podany proces nie istnieje.

gen_server:abcast(Nodes, Name, Request)

Podobnie jak w przypadku multi_call - wysyła do nazwanych serwerów Name na węzłach Nodes. Ignoruje wszelkie niepowodzenia. Zawsze zwraca atom abcast.

Wysyłanie odpowiedzi

gen_server:reply(Client, Reply)

Wysyła komunikat Reply do procesu Client, który został przekazany do wywołania zwrotnego jako From. Wynik należy ignorować.

Funkcje zwrotne

Wynik

Znaczenie pól w krotce wyniku:

  • NewState - dowolne wyrażenie reprezentujące nowy stan wewnętrzny serwera;
  • atom hibernate - proces będzie czekał na następny komunikat będąc zamrożonym;
  • wartość Timeout - jeśli w ciągu odpowiedniej ilości milisekund do procesu nie przyjdzie żadne żądanie, to do Module:handle_info/2 zostanie wysłany komunikat timeout

Dla wywołań synchronicznych

{reply,Reply,NewState}
{reply,Reply,NewState,Timeout}
{reply,Reply,NewState,hibernate}
{stop,Reason,Reply,NewState}

Oznaczają, że nasz serwer:

  • odeśle komunikat Reply do wysyłającego,
  • zmieni stan wewnętrzny na NewState,
  • dla stop:
    • wywoła funkcję terminate/3 z powodem zakończenia Reason.

Dla wywołań asynchronicznych

{noreply,NewState}
{noreply,NewState,Timeout}
{noreply,NewState,hibernate}
{stop,Reason,NewState}

Oznaczają, że nasz serwer:

  • zmieni stan wewnętrzny na NewState,
  • dla stop:
    • wywoła funkcję terminate/3 z powodem zakończenia Reason.

Inicjalizacja i kończenie

Module:init(Args) -> Result
Module:terminate(Reason, State)
 
Result =
  {ok,State} |
  {ok,State,Timeout} |
  {ok,State,hibernate} |
  {stop,Reason} |
  ignore

Obsługa komunikatów

Jeśli komunikat się nie dopasuje do klauzuli funkcji to serwer się zakończy.

Synchronicznych

Module:handle_call(Request, From, State) -> Result

Powyższa funkcja musi odesłać odpowiedź do procesu From w jeden z dwóch sposób:

  • zwraca krotkę z odpowiedzią,
  • wysyła ręcznie odpowiedź za pomocą wywołania gen_server:reply(From,Reply) i zwraca krotkę bez odpowiedzi.

Asynchronicznych

Module:handle_cast(Request, State) -> Result

Zawsze zwraca krotkę bez odpowiedzi.

Innych

Module:handle_info(Info, State) -> Result

Obsługuje wszystkie pozostałe komunikaty.

Wymiana oprogramowania

Module:code_change(OldVsn, State, Extra) -> {ok, NewState}

Przykład

Serwer zarządzający kanałami komunikacji

 1: -module(chsrv).
 2: -behaviour(gen_server).
 3: -export([start_link/0]).
 4: -export([alloc/0, free/1]).
 5: -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
 6:
 7: start_link() ->
 8:   gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
 9:
10: alloc() ->
11:   gen_server:call(?MODULE, alloc).
12:
13: free(Ch) ->
14:   gen_server:cast(?MODULE, {free, Ch}).
15:
16: channels() ->
17:   lists:map( fun(X) -> {X,free} end, lists:seq(1,10) ).
18:
19: alloc(Chs) ->
20:   case lists:keyfind( free, 2, Chs ) of
21:     {Name,free} ->
22:       {Name, lists:keyreplace(Name, 1, Chs, {Name,busy})};
23:     false ->
24:       {{error,busy}, Chs}
25:   end.
26:
27: free(Name, Chs) ->
28:   case lists:keyfind( Name, 1, Chs ) of
29:     {Name,busy} ->
30:       lists:keyreplace(Name, 1, Chs, {Name,free});
31:     _ ->
32:       Chs
33:   end.
34:
35: init(_Args) ->
36:   {ok, channels()}.
37:
38: handle_call(alloc, _From, State) ->
39:   {Ch, State2} = alloc(State),
40:   {reply, Ch, State2}.
41:
42: handle_cast({free, Ch}, State) ->
43:   State2 = free(Ch, State),
44:   {noreply, State2}.
45:
46: handle_info(Info, State) ->
47:   io:format("Unhandled message: ~p~n", [Info]),
48:   {noreply,State}.
49:
50: terminate(_Reason, _State) ->
51:   ok.
52:
53: code_change(_OldVsn, State, _Extra) ->
54:   {ok, State}.

Źródła

Podręczniki:

Moduły:

 
erlang/otp-server.txt · Last modified: 2010/05/07 17:49 by Krystian Baclawski
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-No Derivative Works 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki