如何实现套接字服务器?

时间:2016-12-21 20:01:05

标签: sockets erlang elixir otp

我正在尝试在监督树中实现套接字服务器。我已将以下内容添加到主要主管:

supervisor(AcceptorSup, [Application.get_env(:appname, :port)])
supervisor(Task.Supervisor, [[name: ClientSupervisor]])

这是AcceptorSup模块

defmodule AcceptorSup do
  use Supervisor
  require Logger

  def start_link(port) do
    Supervisor.start_link __MODULE__, [port: port], name: __MODULE__
  end

  def init(args \\ []) do
    port = Keyword.get args, :port, 8000
    {:ok, socket} = :gen_tcp.listen port, active: false, reuseaddr: true, packet: :raw
    Logger.info "Server started on port #{port}"

    children = [
      worker(Acceptor, [socket], function: :start)
    ]

    num_childs = Application.get_env :appname, :acceptors_num, 50
    for _ <- 1..num_childs do
      Task.start fn ->
        Supervisor.start_child AcceptorSup, []
      end
    end

    supervise(children, strategy: :simple_one_for_one, max_restarts: 1000, max_seconds: 10)
  end
end

以下是Acceptor

的基本代码
defmodule Acceptor do
  require Logger

  def start(socket) when is_port(socket) do
    Task.start_link fn -> serve_client(socket) end
  end

  defp serve_client(socket) when is_port(socket) do
    {:ok, client} = :gen_tcp.accept socket
    Logger.info "A client connected #{address client}"
    {:ok, pid} = Task.Supervisor.start_child ClientSupervisor, fn -> serve(client) end
    :ok = :gen_tcp.controlling_process client, pid
    Supervisor.start_child AcceptorSup, []
  end
end

所以,我开始一个Task.Supervisor来处理客户端,这很好。我还启动了一个类型simple_one_for_one的主管来处理监听器。每个孩子等待连接,并在给出时,在任务主管中为客户生成任务并启动另一个孩子而不是自己。问题是如果客户端连接和断开连接的速率足够高,主管就会崩溃,因为它会达到max_restartsmax_seconds的值。我可以通过增加值来增加阈值,但它对我来说似乎不对。我正在寻找一种方法来处理客户端的连接和断开连接,而不是达到这些限制。

如何实现这一点,同时尊重监督树?我不想使用自定义流程管理,因为我几乎可以肯定这里有一些我不知道的东西。无论如何,Erlang / OTP旨在解决这些问题,对吗?

0 个答案:

没有答案