在spawn,{error,closed}之后,tcp Socket在erlang中的远程节点上没有工作?

时间:2015-11-29 09:47:44

标签: sockets tcp erlang

问题是我在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

远程节点也可以在另一台机器上? 我做错了什么?或者是可能的, 对不起英语薄弱,提前谢谢! ;)

2 个答案:

答案 0 :(得分:3)

节点无法在它们之间传递套接字。如果你想一下,这应该是显而易见的。机器被分配地址A和另一个地址B.A上的节点接受TCP连接,然后尝试将端口传递给B.由于操作系统,硬件和所有网络设备的网络层,因此无法工作。认为在机器 A和客户端所在的机器之间存在TCP连接。

是的, 是神奇的方法,使其不那么真实,将网络从硬件中抽象出来等等。但这不是典型的情况,也没有制作这些东西所必需的基础设施发生的事件对Erlang VM可见。您可能确实在本地计算机上进行了测试,但再一次,这不是典型情况(不值得支持作为功能),并且VM级别的节点本身将具有批次难以确定是否可以安全地以一种跨平台(Linux,Windows,OSX,BSD,Solaris等)的方式安全地传递端口。

所以......端口不是Erlang节点可以按照它们的方式无缝传递的东西,比如元组。同样的规则适用于其他硬件绑定资源,如打开文件,进程端口等。

答案 1 :(得分:0)

一个非常有趣的例子!套接字绑定到正在侦听给定端口的OS进程(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}]}]}

要完成您想要完成的任务,您需要使用代理服务器&#39;进程从套接字接收消息并将它们发送到另一个节点。

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