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

Posted

技术标签:

【中文标题】生成后,Tcp Socket 在 erlang 中的远程节点上不起作用,错误,关闭?【英文标题】:Tcp Socket is not working on remote node in erlang after spawn, error, closed?生成后,Tcp Socket 在 erlang 中的远程节点上不起作用,错误,关闭? 【发布时间】:2016-03-03 01:46:24 【问题描述】:

您好,问题是我在 erlang 中创建了一个 tcp 服务器套接字,然后在接受该套接字后,我想在另一个节点上处理它,但它给出了 error, closed。

一个小演示:-

-module(tcp_server).
-compile(export_all). %% just for testing

start() ->
    ok, ListeningSocket = gen_tcp:listen(4444, [active, false, binary]),
    wait_for_next(ListeningSocket).

wait_for_next(ListeningSocket) ->
    %% waiting for requests
    ok, Socket = gen_tcp:accept(ListeningSocket),
    _ = spawn('remote@127.0.0.1', ?MODULE, handle_request, [Socket]),
    wait_for_next(ListeningSocket).

handle_request(Socket) ->
    ok, Data = gen_tcp:recv(Socket, 0), %% this always return error, closed ??
    io:format("~p~n", [Data]),
    gen_tcp:close(Socket).

启动服务器:

erl -name server@127.0.0.1
c(tcp_server).                  %% compile and load
tcp_server:start().             %% started

远程节点:

erl -name remote@127.0.0.1
c(tcp_server).                 %% so here handle_request has been loaded

远程节点也可以在另一台机器上? 我在做什么错?或者这可能吗, 抱歉英语不好,提前感谢! ;)

【问题讨论】:

【参考方案1】:

节点不能在它们之间传递套接字。如果您考虑一下,这应该是显而易见的。一台机器被分配地址 A,另一个地址 B。A 上的节点接受 TCP 连接,然后尝试将端口传递给 B。这永远无法工作,因为操作系统、硬件和所有网络事物的网络层在两者之间相信 机器 A 和客户端所在的机器之间存在 TCP 连接。

是的, 有一些神奇的方法可以让这种情况变得不那么真实,将网络从硬件中抽象出来,等等。但这不是典型的情况,并且没有必要的基础设施来制作这些东西发生对 Erlang VM 是可见的。您在本地机器上进行测试可能是真的,但这又不是典型情况(不值得作为一项功能支持),并且 VM 级别的节点本身会有一个 lot 难以确定是否可以以一种跨平台(Linux、Windows、OSX、BSD、Solaris 等)一致工作的方式在彼此之间安全地传递端口。

所以...端口不是 Erlang 节点之间可以像元组那样无缝传递的东西。相同的规则适用于其他硬件绑定资源,例如打开的文件、进程端口等。

【讨论】:

【参考方案2】:

一个非常有趣的例子!套接字绑定到正在侦听给定端口的操作系统进程(Beam VM)。

虽然分布式 Erlang 的精神表明 Socket 就像任何其他进程一样,并且可以跨 Erlang 节点透明地使用,但事实并非如此。

我在您的代码中添加了一些额外的调试信息,以表明传递给不同节点的套接字对象无法以任何有意义的方式访问:

wait_for_next(ListeningSocket) ->
    ok, Socket = gen_tcp:accept(ListeningSocket),
    error_logger:info_msg("Socket info: ~p~n", [inet:sockname(Socket)]),
    gen_tcp:controlling_process(
        Socket,
        spawn('remote@127.0.0.1', ?MODULE, handle_request, [Socket])),
    wait_for_next(ListeningSocket).

handle_request(Socket) ->
    error_logger:info_msg("Socket info: ~p~n", [inet:sockname(Socket)]),
    ok, Data = gen_tcp:recv(Socket, 0),
    io:format("~p~n", [Data]),
    gen_tcp:close(Socket).

现场直播给了我们:

$ erlc ./tcp_server.erl && erl -name server@127.0.0.1 -s tcp_server start
Eshell V5.9.3  (abort with ^G)
(server@127.0.0.1)1> 
=INFO REPORT==== 29-Nov-2015::18:17:08 ===
Socket info: ok,127,0,0,1,4444
(server@127.0.0.1)1> 
=INFO REPORT==== 29-Nov-2015::18:17:08 ===
Socket info: error,einval
** at node remote@127.0.0.1 **
(server@127.0.0.1)1> 
=ERROR REPORT==== 29-Nov-2015::18:17:08 ===
Error in process <0.43.0> on node 'remote@127.0.0.1' with exit value: badmatch,error,closed,[tcp_server,handle_request,1,[file,"tcp_server.erl",line,18]]

要完成您想做的事情,您需要使用“代理”进程从套接字接收消息并将它们发送到另一个节点。

[Socket] ---> [Proxy] ---> |NODE BOUNDARY| ---> [Handler]

【讨论】:

以上是关于生成后,Tcp Socket 在 erlang 中的远程节点上不起作用,错误,关闭?的主要内容,如果未能解决你的问题,请参考以下文章

在erlang中中断gen_tcp:recv

使用 gen_tcp 的 Erlang 客户端-服务器示例未收到任何内容

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

erlang 发送套接字西里尔文数据

Erlang同时连接1M客户端

使用不止一种 erlang 行为