tcp - Erlang Pattern 接收器

  显示原文与译文双语对照的内容
0 0

考虑以下内容( 基于LYSE中的sockserv )


%%% The supervisor in charge of all the socket acceptors.
-module(tcpsocket_sup).
-behaviour(supervisor).

-export([start_link/0, start_socket/0]).
-export([init/1]).

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

init([]) ->
 {ok, Port} = application:get_env(my_app,tcpPort),
 {ok, ListenSocket} = gen_tcp:listen(
 Port,
 [binary, {packet, 0}, {reuseaddr, true}, {active, true} ]),
 lager:info(io_lib:format("Listening for TCP on port ~p", [Port])),
 spawn_link(fun empty_listeners/0),
 {ok, {{simple_one_for_one, 60, 3600},
 [{socket,
 {tcpserver, start_link, [ListenSocket]},
 temporary, 1000, worker, [tcpserver]}
 ]}}.

start_socket() ->
 supervisor:start_child(?MODULE, []).%,

empty_listeners() ->
 [start_socket() || _ <- lists:seq(1,20)],
 ok.



%%%-------------------------------------------------------------------
%%% @author mylesmcdonnell
%%% @copyright (C) 2015, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 06. Feb 2015 07:49
%%%-------------------------------------------------------------------
-module(tcpserver).
-author("mylesmcdonnell").

-behaviour(gen_server).

-record(state, {
 next,
 socket}).

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

-define(SOCK(Msg), {tcp, _Port, Msg}).
-define(TIME, 800).
-define(EXP, 50).

start_link(Socket) ->
 gen_server:start_link(?MODULE, Socket, []).

init(Socket) ->
 gen_server:cast(self(), accept),
 {ok, #state{socket=Socket}}.

handle_call(_E, _From, State) ->
 {noreply, State}.

handle_cast(accept, S = #state{socket=ListenSocket}) ->
 {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
 kvstore_tcpsocket_sup:start_socket(),
 receive
 {tcp, Socket, <<"store",Value/binary>>} ->
 Uid = kvstore:store(Value),
 send(Socket,Uid);
 {tcp, Socket, <<"retrieve",Key/binary>>} ->
 case kvstore:retrieve(binary_to_list(Key)) of
 [{_, Value}|_] ->
 send(Socket,Value);
 _ ->
 send(Socket,<<>>)
 end;
 {tcp, Socket, _} ->
 send(Socket,"INVALID_MSG")
 end,
 {noreply, S#state{socket=AcceptSocket, next=name}}.

handle_info(_, S) ->
 {noreply, S}.

code_change(_OldVsn, State, _Extra) ->
 {ok, State}.

terminate(normal, _State) ->
 ok;
terminate(_Reason, _State) ->
 lager:info("terminate reason: ~p~n", [_Reason]).

send(Socket, Bin) ->
 ok = gen_tcp:send(Socket, Bin),
 ok = gen_tcp:close(Socket),
 ok.

我不清楚每个tcpserver过程是如何终止的? 这是泄漏过程?

时间: 原作者:

0 0

我没有看到你正在终止所属进程的任何位置。

我想你要找的是四种情况:

  • 客户端终止连接( 你接收 tcp_closed )
  • 连接不稳定( 你收到 tcp_error )
  • 服务器接收到一个系统消息终止( 当然可以,只是管理员杀死它或者消息消息)
  • 客户端发送一条消息告诉服务器完成了一些操作,而你想要做的不仅仅是响应 tcp_closed

最常见的情况通常是客户端关闭连接,因此你需要类似的内容:


handle_info({tcp_closed, _}, State) ->
 {stop, normal, State};

连接变得古怪总是有可能的。 我想不到任何时间我想拥有所有的进程或者插座,所以:


%% You might want to log something here.
handle_info({tcp_error, _}, State) ->
 {stop, normal, State};

在客户机告诉服务器完成并且你需要基于客户端完成清理的任何情况下,你需要从客户端获得成功消息,并返回客户端的成功消息,然后返回 {stop, normal, State}

这里的关键是确保你确定要结束连接的情况,要么让服务器进程终止或者( 更佳) 返回 {stop, Reason, State}

如上所述,如果你希望 send/2 成为单个响应和清洁退出( 实际上,每个 accept 转换都应该产生一个 send/2,然后终止),则需要:


handle_cast(accept, S = #state{socket=ListenSocket}) ->
 {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
 kvstore_tcpsocket_sup:start_socket(),
 receive
 %% stuff that results in a call to send/2 in any case.
 end,
 {stop, normal, S}.

案例LYSE演示了连接是持久的,在客户端和服务器之间正在进行 back-and-forth 。 在上面的一个请求中,生成一个新侦听器,用于填充侦听器池,因为你没有进行任何更进一步的工作。

原作者:
...