生成后,Tcp 套接字无法在 erlang 中的远程节点上工作,{错误,关闭}?
Tcp Socket is not working on remote node in erlang after spawn, {error, closed}?
嗨,问题是我在 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
远程节点也可以在另一台机器上?
我做错了什么?或者有可能吗,
抱歉英语不好,提前致谢! ;)
节点之间不能传递套接字。如果你仔细想想,这应该是显而易见的。一台机器被分配地址 A,另一个地址 B。A 上的节点接受 TCP 连接,然后尝试将端口传递给 B。这永远行不通,因为 OS 的网络层、硬件和两者之间的所有网络事物都相信 机器 A 和客户端所在的机器之间存在 TCP 连接。
是的,有 神奇的方法可以使这种情况变得不那么真实,将网络从硬件中抽象出来等等。但这不是典型的情况,none 使这些事情发生所必需的基础设施的一部分对于 Erlang VM 是可见的。您可能确实在本地机器上进行测试,但再一次,这不是典型情况(不值得作为一项功能支持),并且 VM 级别的节点本身将有 lot 难以确定是否可以以跨平台一致工作的方式安全地相互传递端口(Linux、Windows、OSX、BSD、Solaris、等)。
所以...端口不是 Erlang 节点可以像元组那样在彼此之间无缝传递的东西。同样的规则适用于其他硬件绑定资源,例如打开的文件、进程端口等。
一个很有趣的例子!套接字绑定到正在侦听给定端口的 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}]}]}
要完成您想完成的事情,您需要使用 'proxy' 进程从套接字接收消息并将它们发送到另一个节点。
[Socket] ---> [Proxy] ---> |NODE BOUNDARY| ---> [Handler]
嗨,问题是我在 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
远程节点也可以在另一台机器上? 我做错了什么?或者有可能吗, 抱歉英语不好,提前致谢! ;)
节点之间不能传递套接字。如果你仔细想想,这应该是显而易见的。一台机器被分配地址 A,另一个地址 B。A 上的节点接受 TCP 连接,然后尝试将端口传递给 B。这永远行不通,因为 OS 的网络层、硬件和两者之间的所有网络事物都相信 机器 A 和客户端所在的机器之间存在 TCP 连接。
是的,有 神奇的方法可以使这种情况变得不那么真实,将网络从硬件中抽象出来等等。但这不是典型的情况,none 使这些事情发生所必需的基础设施的一部分对于 Erlang VM 是可见的。您可能确实在本地机器上进行测试,但再一次,这不是典型情况(不值得作为一项功能支持),并且 VM 级别的节点本身将有 lot 难以确定是否可以以跨平台一致工作的方式安全地相互传递端口(Linux、Windows、OSX、BSD、Solaris、等)。
所以...端口不是 Erlang 节点可以像元组那样在彼此之间无缝传递的东西。同样的规则适用于其他硬件绑定资源,例如打开的文件、进程端口等。
一个很有趣的例子!套接字绑定到正在侦听给定端口的 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}]}]}
要完成您想完成的事情,您需要使用 'proxy' 进程从套接字接收消息并将它们发送到另一个节点。
[Socket] ---> [Proxy] ---> |NODE BOUNDARY| ---> [Handler]