转载请注明,来自:http://blog.csdn.net/skyman_2001
Erlang中的Pid/Socket有本地和远程之分,它们之间的区别是什么?
对Pid来说,是格式,其中A为0表示本地节点,为其他值表示远程节点(值为该远程节点在dist_entry中的内部索引);B为4字节无符号整数,代表的是进程id(index,范围是0~MAXPROCS,这里MAXPROCS等于32767);C为4个字节,为Serial(当B达到MAXPROCS时,C就增加)。
对Socket来说,是#Port,其中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)则是可以的,客户端会成功收到数据(见上图中的蓝色方框内容)。
阅读(1945) | 评论(0) | 转发(0) |