Erlang 如何禁用两个节点在同一端口上连接?

Erlang 如何禁用两个节点在同一端口上连接?,erlang,elixir,gen-tcp,Erlang,Elixir,Gen Tcp,我正在制作一个multichat应用程序,下面是示例。在这个应用程序中,我创建了一个服务器,下面是代码: 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 "Accept

我正在制作一个multichat应用程序,下面是示例。在这个应用程序中,我创建了一个服务器,下面是代码:

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
defmodule Multichat.ClientConnection do
使用GenServer
def start_链接(套接字),do:GenServer.start_链接(_模块,套接字)
def init(init_arg)do
{:好的,init_arg}
结束
def handle_调用({:send,message},_from,socket)do
:gen_tcp.send(套接字、消息)
{:reply,:ok,socket}
结束
def handle_info({:tcp,_socket,message},socket)do

对于linux中的{,pid,{,{,},侦听套接字绑定到设备的任何IP或所有IP(1),通常默认为侦听所有IP(
0.0.0
IP)。 一旦进程在一个
ip:port
中侦听,其他套接字就无法在同一
ip:port
中侦听(2)

(1) 这并不完全正确,因为您有网络名称空间和IP_FREEBIND选项。 (2) 同样,也不完全正确,您有一个SO_REUSEPORT套接字选项

因此,在这种情况下,您有几种选择:

  • 为每个要在本地启动的节点设置不同的端口,例如,使用环境变量
  • 在开发过程中,为每个节点监听不同的IP,例如,
    127.0.0.1
    127.0.0.2
  • 在侦听套接字中设置SO_REUSEPORT选项
  • 使用docker或其他容器/命名空间技术,可以在不同的网络命名空间中启动不同的节点
  • 插座选项说明如下
    在Erlang中,相对较新的版本似乎有可用的
    reuseport
    选项,而从中,似乎
    SO\u reuseport
    仅作为
    raw
    选项可用