2011-05-03 21 views
2

所以,我花了很多時間和地段仍然沒有找到答案。二郎:gen_server崩潰時開始了主管

我在gen_server簡單的TCP服務器,它通過telnet接受消息,並在控制檯打印出來:

-module(st_server). 

-behaviour(gen_server). 
%% -------------------------------------------------------------------- 
%% Include files 
%% -------------------------------------------------------------------- 

%% -------------------------------------------------------------------- 
%% External exports 
-export([start_link/0, start_link/1, stop/0]). 

%% gen_server callbacks 
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). 

-define(SERVER, ?MODULE). 
-define(DEFAULT_PORT, 1055). 

-record(state, {lsock, port}). 

%% ==================================================================== 
%% External functions 
%% ==================================================================== 

%%-------------------------------------------------------------------- 
%% @doc Starts the server. 
%% 
%% @spec start_link(Port::integer()) -> {ok, Pid} 
%% where 
%% Pid = pid() 
%% @end 
%%-------------------------------------------------------------------- 
start_link(Port) -> 
    gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []), 
    io:format("Server name: ~w, port: ~w.~n", [?SERVER, Port]). 

%% @spec start_link() -> {ok, Pid} 
%% @doc Calls `start_link(Port)' using the default port. 
start_link() -> start_link(?DEFAULT_PORT). 

%%-------------------------------------------------------------------- 
%% @doc Stops the server. 
%% @spec stop() -> ok 
%% @end 
%%-------------------------------------------------------------------- 
stop() -> 
    gen_server:cast(?SERVER, stop). 

%% ==================================================================== 
%% Server functions 
%% ==================================================================== 

%% -------------------------------------------------------------------- 
%% Function: init/1 
%% Description: Initiates the server 
%% Returns: {ok, State}   | 
%%   {ok, State, Timeout} | 
%%   ignore    | 
%%   {stop, Reason} 
%% -------------------------------------------------------------------- 
init([Port]) -> 
    {ok, LSock} = gen_tcp:listen(Port, [{active, true}]), 
    {ok, #state{lsock = LSock, port = Port}, 0}. 

%% -------------------------------------------------------------------- 
%% Function: handle_cast/2 
%% Description: Handling cast messages 
%% Returns: {noreply, State}   | 
%%   {noreply, State, Timeout} | 
%%   {stop, Reason, State}   (terminate/2 is called) 
%% -------------------------------------------------------------------- 
handle_cast(stop, State) -> 
    {stop, normal, State}. 

handle_call(_Request, _From, State) -> 
    {reply, ok, State}. 

%% -------------------------------------------------------------------- 
%% Function: handle_info/2 
%% Description: Handling all non call/cast messages 
%% Returns: {noreply, State}   | 
%%   {noreply, State, Timeout} | 
%%   {stop, Reason, State}   (terminate/2 is called) 
%% -------------------------------------------------------------------- 


handle_info({tcp, _Socket, Data}, State) -> 
    io:format("Incoming info: ~s", [Data]), 
    {noreply, State}; 

handle_info({tcp_closed, _Socket}, #state{lsock = LSock} = State) -> 
    {ok, _Sock} = gen_tcp:accept(LSock), 
    {noreply, State}; 

handle_info(timeout, #state{lsock = LSock} = State) -> 
    {ok, _Sock} = gen_tcp:accept(LSock), 
    {noreply, State}. 

%% -------------------------------------------------------------------- 
%% Function: terminate/2 
%% Description: Shutdown the server 
%% Returns: any (ignored by gen_server) 
%% -------------------------------------------------------------------- 
terminate(Reason, _State) -> 
    io:format("~nServer shutdown. Reason: ~s.~n", [Reason]), 
    ok. 

%% -------------------------------------------------------------------- 
%% Func: code_change/3 
%% Purpose: Convert process state when code is changed 
%% Returns: {ok, NewState} 
%% -------------------------------------------------------------------- 
code_change(_OldVsn, _State, _Extra) -> 
    {ok, _State}. 

%% -------------------------------------------------------------------- 
%%% Internal functions 
%% -------------------------------------------------------------------- 

,監事:

-module(st_sup). 

-behaviour(supervisor). 
%% -------------------------------------------------------------------- 
%% Include files 
%% -------------------------------------------------------------------- 

%% -------------------------------------------------------------------- 
%% External exports 
%% -------------------------------------------------------------------- 
-export([]). 

%% -------------------------------------------------------------------- 
%% Internal exports 
%% -------------------------------------------------------------------- 
-export([ 
    init/1, 
    start_link/0 
     ]). 

%% -------------------------------------------------------------------- 
%% Macros 
%% -------------------------------------------------------------------- 
-define(SERVER, ?MODULE). 

%% -------------------------------------------------------------------- 
%% Records 
%% -------------------------------------------------------------------- 

%% ==================================================================== 
%% External functions 
%% ==================================================================== 

start_link() -> 
    supervisor:start_link({local, ?SERVER}, ?MODULE, []). 

%% ==================================================================== 
%% Server functions 
%% ==================================================================== 
%% -------------------------------------------------------------------- 
%% Func: init/1 
%% Returns: {ok, {SupFlags, [ChildSpec]}} | 
%%   ignore       | 
%%   {error, Reason} 
%% -------------------------------------------------------------------- 
init([]) -> 
    Server = {st_server, {st_server, start_link, []}, 
       permanent, 2000, worker, [st_server]}, 
    Children = [Server], 
    RestartStrategy = {one_for_one, 0, 1}, 
    {ok, {RestartStrategy, Children}}. 

%% ==================================================================== 
%% Internal functions 
%% ==================================================================== 

我在二郎控制檯啓動此:

st_sup:start_link(). 

而得到這樣的:

Server name: st_server, port: 1055. 
** exception exit: shutdown 

這意味着,監事關閉服務器由於某種原因。 如果我開始通過自身的服務器(st_server:START_LINK)它工作得很好。

所以,問題是如何使沒有停工這項工作?

回答

5

一眼就可能是因爲st_server:start_link/1的返回值是io:format/2調用的返回值。

當你直接在REPL打電話st_server:start_link(),但超級大概是期待一個返回值更像{ok, Pid}這是好的。

您可以只用在st_server:start_link/1交換兩行解決這個問題,所以它調用的值返回到gen_server:start_link/4

start_link(Port) ->  
    io:format("Server name: ~w, port: ~w.~n", [?SERVER, Port]), 
    gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []). 
+0

哦,我的天哪!而已!謝謝) – Dimitry 2011-05-03 19:53:21

+0

但這是一種奇怪的像C,Java的順序語言。這意味着,主管會跟蹤所有輸出通道。 – Dimitry 2011-05-03 19:55:28

+0

我不確定「跟蹤所有輸出通道」的含義。但是,函數的返回值總是最後一個表達式,包括當它是'IO:format',其中有一個返回值'ok'。 – 2011-05-03 20:23:42

1

一個奇怪的值也被設置爲{one_for_one,0,1}主管的RestartStrategy。這意味着主管將在1秒內重啓超過零後放棄,實際上它會在孩子第一次崩潰後放棄。這通常不是你想要一位主管做的事情。

+1

(我可能是錯的,但看起來他改編自書「Erlang和OTP在行動」,它具有精確'RestartStrategy'並解釋說,這不是一個正常的配置的例子。) – 2011-05-03 21:48:47

+0

@Ben詹姆斯·您「R右=),我這樣做是爲了調試的目的。 – Dimitry 2011-05-06 08:14:47