转载请注明,来自:http://blog.csdn.net/skyman_2001
Erlang中的Pid/Socket有本地和远程之分,它们之间的区别是什么?
对Pid来说,是<A.B.C>格式,其中A为0表示本地节点,为其他值表示远程节点(值为该远程节点在dist_entry中的内部索引);B为4字节无符号整数,代表的是进程id(index,范围是0~MAXPROCS,这里MAXPROCS等于32767);C为4个字节,为Serial(当B达到MAXPROCS时,C就增加)。
对Socket来说,是#Port<A.B>,其中A和Pid中的A一样,为0表示本地Socket,为其他值表示远程Socket;B为Socket index。
当Pid/Socket在进程间传送时,如果是跨节点,Erlang会自动把传过来的本地Pid/Socket转换成远程Pid/Socket。
那能不能直接使用远程Pid/Socket呢?经过我的测试,得出的结论是:Pid能;Socket不能。下面是测试的代码:
1. tcp_server.erl(注:这个是根据http://blog.163.com/myerlang@126/blog/static/16454075820105288592327/的代码稍微改写了一下)
-module(tcp_server).
-export([nano_client_eval/1, start_nano_server/1]).
nano_client_eval(Str) ->
{ok,Socket}=gen_tcp:connect("localhost",2345,[binary,{packet,4}]),
io:format("=== client socket: ~p~n", [Socket]),
ok=gen_tcp:send(Socket,term_to_binary(Str)),
loop1(Socket).
loop1(Socket) ->
receive
{tcp,Socket,Bin} ->
io:format("Client received binary = ~p~n",[Bin]),
Val=binary_to_term(Bin),
io:format("Client result = ~p~n",[Val]),
% gen_tcp:close(Socket)
loop1(Socket);
_ ->
skip
end.
start_nano_server(Pid) ->
{ok,Listen}=gen_tcp:listen(2345,[binary,{packet,4},
{reuseaddr,true},
{active,true}]),
{ok,Socket}=gen_tcp:accept(Listen),
io:format("=== socket: ~p~n", [Socket]),
gen_tcp:close(Listen),
gen_tcp:send(Socket,term_to_binary("test local socket")),
Pid ! {sock, Socket},
loop2(Socket).
loop2(Socket) ->
receive
{tcp,Socket,Bin} ->
io:format("Server received binary = ~p~n",[Bin]),
Str=binary_to_term(Bin),
io:format("Server (unpacked) ~p~n",[Str]),
gen_tcp:send(Socket,term_to_binary(Str)),
gen_tcp:send(Socket,term_to_binary("one more msg")),
loop2(Socket);
{tcp_closed,Socket} ->
io:format("Server socket closed~n")
end.
2. msg_test.erl
-module(msg_test).
-export([loop/0, send/1]).
loop() ->
receive
{start_server, From} ->
io:format("---start_server,from:~p~n", [From]),
tcp_server:start_nano_server(From);
{msg, D} ->
io:format("---~p~n", [D]),
loop();
_Other ->
loop()
end.
send(Pid) ->
Pid ! {start_server, self()},
receive
{sock, Socket} ->
io:format("---sock: ~p~n", [Socket]),
io:format("---send remote socket: ~n"),
Res = gen_tcp:send(Socket,term_to_binary("test remote socket")),
io:format("---Result: ~p~n", [Res]);
_Other ->
error
end.
运行测试截图:
上图中红圈旁的序号表示操作的先后步骤。
由测试结果可以得出最终结论:
1. 直接用远程Pid向这个进程发消息是可以的,形如:Remote_pid ! Msg,就能把Msg消息发送到其他节点的这个进程上;
2. 用gen_tcp:send(Remote_socket, Bin)向该Socket发数据是不行的,会返回{error, closed}错误;而gen_tcp:send(Local_socket, Bin)则是可以的,客户端会成功收到数据(见上图中的蓝色方框内容)。