erlang 如何禁用两个节点连接到同一端口?

2ic8powd  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(174)

我正在制作一个多聊天应用程序,这里是code。在这个应用程序中,我制作了一个服务器,这里是代码:

defmodule Multichat.Server do
  require Logger

  def accept(port) do
    {:ok, socket} = :gen_tcp.listen(port, [:binary, packet: :line, active: true, reuseaddr: true])
    Logger.info "Accepting connections on port #{port}"
    loop_acceptor(socket)
  end

  defp loop_acceptor(socket) do
    {:ok, client} = :gen_tcp.accept(socket)
    {:ok, pid} = DynamicSupervisor.start_child(Multichat.Server.ConnectionSupervisor, {Multichat.ClientConnection, client})
    :ok = :gen_tcp.controlling_process(client, pid)
    loop_acceptor(socket)
  end
end

您可以在代码中看到一个客户端部分:

defmodule Multichat.ClientConnection do
  use GenServer

  def start_link(socket), do: GenServer.start_link(__MODULE__, socket)
  def init(init_arg) do
    {:ok, init_arg}
  end

  def handle_call({:send, message}, _from, socket) do
    :gen_tcp.send(socket, message)
    {:reply, :ok, socket}
  end

  def handle_info({:tcp, _socket, message}, socket) do
    for {_, pid, _, _} <- DynamicSupervisor.which_children(Multichat.Server.ConnectionSupervisor) do
      if pid != self() do
        GenServer.call(pid, {:send, message})
      end
    end

    {:noreply, socket}
  end
end

我想当我在一个端口上启动一个节点时,另一个节点不能不连接到另一个端口上。这怎么可能呢?

mqxuamgl

mqxuamgl1#

In linux, listening sockets are bound to any of the device's IP or all of them (1), usually the default being listening in all of them (the 0.0.0.0 ip). Once a process is listening in one ip:port , no other socket is able to listen in the same ip:port (2)
(1) This is not entirely true, because you have network namespaces and the IP_FREEBIND option. (2) Again, not entirely true, you have the SO_REUSEPORT socket option.
So, in this case you have several options:

  1. Set different ports for each node to be started locally, for example, using environment variables
  2. Listen in different IPs for each node during development, for example, 127.0.0.1 and 127.0.0.2
  3. Set the SO_REUSEPORT option in the listening sockets
  4. Use docker or other container/namespace technology to be able to start different nodes in different network namespaces.
    Socket options are explained here
    In Erlang, it seems that the relatively new low-level socket API has the reuseport option available, whereas, from the inet documentation (gen_tcp), it seems that SO_REUSEPORT is only available as a raw option.

相关问题