如何停止在erlang中作为gen_server实现的tcp_listener

Posted

技术标签:

【中文标题】如何停止在erlang中作为gen_server实现的tcp_listener【英文标题】:How to stop a tcp_listener implemented as a gen_server in erlang 【发布时间】:2016-07-26 01:56:38 【问题描述】:

我将 tcp_listener 实现为 gen_server()。我有一个名为 start_link(Port) 的函数在该端口创建一个 tcp_listener。现在,我很难理解如何通过 stop() 告诉 tcp_listener 停止监听。 我尝试使用 stop 调用这样的函数。

 stop() -> gen_server:cast(?MODULE, shutdown) 

在 terminate/2 函数中,我尝试关闭侦听套接字但失败了。

 terminate(_Reason, State = #statelsocket = LSocket) ->
 gen_tcp:close(LSocket),
 NewState = State#statelsocket = null,
 ok, NewState.

如果我关闭侦听套接字,我生成的已接受连接会发生什么情况。

谢谢!

   start_link(Port) when is_integer(Port) ->
   State = #stateport = Port,
   gen_server:start_link(local, ?MODULE, ?MODULE, State, []).

  init(State = #stateport = Port) ->
  io:format("Supervisor started me and I am listening at ~p ~n", [Port]),
  case gen_tcp:listen(Port, ?TCP_OPTIONS) of
    ok, LSocket ->
     NewState = State#statelsocket = LSocket,
     spawn(fun() -> accept(NewState) end),
     ok, NewState;
    error, Reason ->
     stop, Reason
   end.

   accept(State = #statelsocket = LSocket) ->
   case gen_tcp:accept(LSocket) of
   ok, Socket ->
    Pid = spawn(fun() ->
    io:format("Connection accepted ~n"),
    loop(Socket)
              end),
    gen_tcp:controlling_process(Socket, Pid),
    accept(State);
    error, closed -> error
    end.

     loop(Socket) ->
    case gen_tcp:recv(Socket, 0) of
      ok, Data ->
       gen_tcp:send(Socket, Data),
     loop(Socket);
    error, closed ->
       ok
     end.

【问题讨论】:

您不会产生连接,只会产生一个进程。如果关闭套接字,所有连接都将被丢弃。您实际上是否在生成任何进程? 是的,我实际上是在生成进程。如果我接受连接,我将产生一个新进程。因此,稍后即使我关闭了监听套接字,我也可以在发送和接收消息时使用已接受的套接字(在我的情况下为 echo_server)。请参考代码,现已编辑。 【参考方案1】:

我建议你看看this chapter in the Learn You Some Erlang book,尤其是:

两个套接字可以以相同的方式发送消息,然后可以用gen_tcp:close(Socket) 关闭。请注意,关闭接受套接字将单独关闭该套接字,而关闭侦听套接字将不会关闭任何相关且已建立的接受套接字,但会通过返回 error, closed 来中断当前正在运行的接受调用。

所以这应该只是在所有套接字上调用gen_tcp:close(Socket) 的问题。

【讨论】:

感谢 amiramix。现在有道理了。如何将所有接受的套接字存储为状态的一部分,然后在调用 stop() 时关闭所有这些套接字。这是一个坏方法吗? 不,一点也不,它们必须存储在父母或每个孩子的状态中。只是不要忘记,一旦套接字关闭并且进程尝试使用它,它将得到一个错误,您必须能够处理。 谢谢!我实现为一个 ets 表,而不是状态的一部分,它存储所有连接的套接字,然后关闭它们中的每一个。

以上是关于如何停止在erlang中作为gen_server实现的tcp_listener的主要内容,如果未能解决你的问题,请参考以下文章

Erlang:如何在主管中正确调度带有 start_child 的 gen_server 并调用 API

如何在 erlang gen_server 中有效地使用接收子句来解决超时错误?

在 Erlang 的 gen_server 中实现代码交换

Erlang gen_server:如何捕获错误?

难以理解 Erlang Gen_Server 架构

如何直观地描述 gen_server?