在 Erlang 中通过 RPC 在远程节点上创建套接字时,无法接受套接字上的连接

Posted

技术标签:

【中文标题】在 Erlang 中通过 RPC 在远程节点上创建套接字时,无法接受套接字上的连接【英文标题】:Unable to accept connections on socket, when creating sockets on remote node via RPC in Erlang 【发布时间】:2015-09-20 20:43:57 【问题描述】:

我正在努力找出 gen_tcp:accept 总是返回 error, closed 响应的原因。

基本上,我有一个创建监听套接字的主管:

gen_tcp:listen(8081, [binary, packet, 0, active, false, reuseaddr, true]),

这个套接字然后被传递给一个孩子,这是一个 gen_server 行为的实现。然后孩子接受套接字上的连接。

accept(ListeningSocket, ok, Socket) ->                                   
    spawn(fun() -> loop(Socket) end),                                      
    accept(ListeningSocket);
accept(_ListeningSocket, error, Error) ->
    io:format("Unable to listen on socket: ~p.~n", [Error]),
    gen_server:call(self(), stop).

accept(ListeningSocket) ->                                                 
    accept(ListeningSocket, gen_tcp:accept(ListeningSocket)).                                                                                             

loop(Socket) ->                                                            
    case gen_tcp:recv(Socket, 0) of                                        
        ok, Data ->                                                      
            io:format("~p~n", [Data]),                                     
            process_request(Data),                                         
            gen_tcp:send(Socket, Data),                                    
            loop(Socket);                                                  
        error, closed -> ok                                              
   end.

我在本地加载 supervisor 和 gen_server BEAM 二进制文件,并通过对 code:load_binary 的 RPC 调用将它们加载到另一个节点(在同一台机器上运行)。 接下来,我通过 RPC 调用执行主管,然后启动服务器。在这种情况下,gen_tcp:accept 总是返回error, closed。

我是否应该在登录到节点外壳时运行主管和服务器,然后服务器可以毫无问题地接受连接。这包括对无法接受连接的远程节点的“remsh”,如果我之前对其进行了 RPC 以不成功地启动服务器。

我似乎能够通过单独使用 shell 来复制问题:

[Terminal 1]: erl -sname node -setcookie abc -distributed -noshell

[Terminal 2]: erl -sname rpc -setcookie abc:

              net_adm:ping('node@verne').
              ok, ListeningSocket = rpc:call('node@verne', gen_tcp, listen, [8081, [binary, packet, 0, active, true, reuseaddr, true]]).
              rpc:call('node@verne', gen_tcp, accept, [ListeningSocket]).

对最终 RPC 的响应是 error, closed。

这可能与套接字/端口所有权有关吗?

如果有帮助,没有客户端等待连接,我也不会在任何地方设置超时。

【问题讨论】:

【参考方案1】:

每个rpc:call 在目标节点上启动一个新进程来处理请求。在您的最后一个示例中,您的第一个调用在此类进程中创建了一个侦听套接字,并且当该进程在 rpc 调用结束时终止时,该套接字将关闭。因此,由于已关闭的侦听套接字,您尝试接受的第二次 rpc 调用失败。

您的设计在几个方面似乎不同寻常。例如,让主管打开套接字是不正常的。您还说孩子是gen_server,但您显示了手动recv 循环,如果在gen_server 内运行会阻止它。相反,您可以解释您要完成的工作,并请求帮助以设计出满足您的目标的设计。

【讨论】:

这很有道理,史蒂夫。谢谢你的解释。 这个问题出现在不久前,当时我在 Erlang 中尝试使用套接字。我只是没能早点问这个问题。如果我没记错的话,我最初的意图是让多个 gen_servers 在同一个套接字上接受连接。在目标节点上生成了一个新进程来处理请求这一事实解释了为什么在通过 RPC 启动 gen_server 时套接字会立即关闭。

以上是关于在 Erlang 中通过 RPC 在远程节点上创建套接字时,无法接受套接字上的连接的主要内容,如果未能解决你的问题,请参考以下文章

Erlang : RPC 到一个节点,该节点上有输出

生成后,Tcp Socket 在 erlang 中的远程节点上不起作用,错误,关闭?

进程名,节点名!跨 Erlang 节点的消息 VS rpc:call/4 VS HTTP/1.1

Erlang:以编程方式启动远程节点

在 Erlang 中通过 tcp 套接字发送元组

在erlang中向远程节点端口发送消息