Erlang Tcp接受器模式
考虑以下因素(基于LYSE的sockserv)Erlang Tcp接受器模式,tcp,erlang,Tcp,Erlang,考虑以下因素(基于LYSE的sockserv) %%%负责所有套接字接收器的主管。 -模块(tcpsocket\u sup)。 -行为(主管)。 -导出([启动链接/0,启动套接字/0])。 -导出([init/1])。 启动链接()-> 主管:启动链接({local,?MODULE},?MODULE,[])。 init([])-> {ok,Port}=application:get_env(my_app,tcpPort), {ok,ListenSocket}=gen_-tcp:listen(
%%%负责所有套接字接收器的主管。
-模块(tcpsocket\u sup)。
-行为(主管)。
-导出([启动链接/0,启动套接字/0])。
-导出([init/1])。
启动链接()->
主管:启动链接({local,?MODULE},?MODULE,[])。
init([])->
{ok,Port}=application:get_env(my_app,tcpPort),
{ok,ListenSocket}=gen_-tcp:listen(
港口,
[二进制,{packet,0},{reuseaddr,true},{active,true}],
lager:info(io_lib:format(“在端口~p上侦听TCP”,[port]),
生成链接(有趣的空侦听器/0),
{好的,{简单的{u一{u一},60,3600},
[{套接字,
{tcpserver,启动链接,[ListenSocket]},
临时的,1000,工作者,[tcpserver]}
]}}.
启动\u套接字()->
主管:启动子模块(?模块,[])。%,
空侦听器()->
[start_socket()| | |u
gen_服务器:启动链接(?模块,套接字,[])。
初始化(套接字)->
gen_服务器:强制转换(self(),accept),
{好的,#状态{socket=socket}。
处理呼叫(\u E,\u From,State)->
{诺雷普利州}。
handle_cast(accept,S=#state{socket=ListenSocket})->
{ok,AcceptSocket}=gen_tcp:accept(ListenSocket),
kvstore\u tcpsocket\u sup:start\u socket(),
接收
{tcp,套接字,}->
Uid=kvstore:store(值),
发送(套接字,Uid);
{tcp,套接字,}->
案例kvstore:检索
[{uu,Value}{124;]->
发送(套接字、值);
_ ->
发送(套接字,)
结束;
{tcp,套接字,{}->
发送(套接字,“无效消息”)
完,,
{noreply,S#state{socket=AcceptSocket,next=name}。
处理\u信息(\u,S)->
{诺雷普利,S}。
代码更改(_OldVsn,State,_Extra)->
{好的,州政府}。
终止(正常状态)->
好啊
终止(_原因,_状态)->
lager:info(“终止原因:~p~n”,[\u原因])。
发送(套接字、Bin)->
ok=gen_tcp:send(套接字,Bin),
ok=发电机tcp:关闭(插座),
好啊
我不清楚每个tcpserver进程是如何终止的?这是在泄漏进程吗?我看不到任何地方您正在终止自己的进程 我想你要找的是四个案例:
- 客户端终止连接(您收到
)tcp\u closed
- 连接出现问题(您收到
)tcp\u错误
- 服务器接收到要终止的系统消息(当然,这可能只是主管终止它,或者是终止消息)
- 客户端发送一条消息,告诉服务器它已经完成了,您希望进行一些清理,而不仅仅是对
tcp\u关闭做出反应
handle_info({tcp_closed, _}, State) ->
{stop, normal, State};
连接变得奇怪总是有可能的。我想不出任何时候我都想拥有这个进程或套接字,所以:
%% You might want to log something here.
handle_info({tcp_error, _}, State) ->
{stop, normal, State};
在任何情况下,客户机告诉服务器它已经完成了,并且您需要根据客户机已经成功地完成了一些事情来进行清理(可能您打开了应该首先写入的资源,或者打开了一个挂起的DB事务,或者其他什么)您希望从客户端收到一条成功消息,该消息以send/2
的方式关闭连接,并返回{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演示的情况是,连接是持久的,客户端和服务器之间来回进行。在上述情况下,您正在处理单个请求,生成一个新的侦听器以重新填充侦听器池,并且应该退出,因为您不打算让此gen_服务器做任何进一步的工作
%% You might want to log something here.
handle_info({tcp_error, _}, State) ->
{stop, normal, State};
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}.