Chinaunix首页 | 论坛 | 博客
  • 博客访问: 255530
  • 博文数量: 76
  • 博客积分: 66
  • 博客等级: 民兵
  • 技术积分: 980
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-28 16:48
个人简介

做游戏 写程序 Erlang分布式

文章分类

全部博文(76)

文章存档

2017年(3)

2016年(2)

2015年(1)

2014年(5)

2013年(20)

2012年(45)

我的朋友

分类: Erlang

2015-01-16 17:16:47

转载请注明,来自: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/的代码稍微改写了一下)

[plain] view plaincopy
  1. -module(tcp_server).  
  2.   
  3. -export([nano_client_eval/1, start_nano_server/1]).  
  4.   
  5. nano_client_eval(Str) ->  
  6.     {ok,Socket}=gen_tcp:connect("localhost",2345,[binary,{packet,4}]),  
  7.     io:format("=== client socket: ~p~n", [Socket]),  
  8.     ok=gen_tcp:send(Socket,term_to_binary(Str)),  
  9.     loop1(Socket).  
  10.   
  11. loop1(Socket) ->  
  12.     receive  
  13.         {tcp,Socket,Bin} ->  
  14.             io:format("Client received binary = ~p~n",[Bin]),  
  15.             Val=binary_to_term(Bin),  
  16.             io:format("Client result = ~p~n",[Val]),  
  17.             % gen_tcp:close(Socket)  
  18.         loop1(Socket);  
  19.     _ ->  
  20.         skip  
  21.     end.  
  22.   
  23. start_nano_server(Pid) ->  
  24.     {ok,Listen}=gen_tcp:listen(2345,[binary,{packet,4},  
  25.                                             {reuseaddr,true},  
  26.                                             {active,true}]),  
  27.     {ok,Socket}=gen_tcp:accept(Listen),  
  28.     io:format("=== socket: ~p~n", [Socket]),  
  29.     gen_tcp:close(Listen),  
  30.     gen_tcp:send(Socket,term_to_binary("test local socket")),  
  31.     Pid ! {sock, Socket},  
  32.     loop2(Socket).  
  33.   
  34. loop2(Socket) ->  
  35.     receive  
  36.         {tcp,Socket,Bin} ->  
  37.             io:format("Server received binary = ~p~n",[Bin]),  
  38.             Str=binary_to_term(Bin),  
  39.             io:format("Server (unpacked) ~p~n",[Str]),  
  40.             gen_tcp:send(Socket,term_to_binary(Str)),  
  41.             gen_tcp:send(Socket,term_to_binary("one more msg")),  
  42.             loop2(Socket);  
  43.         {tcp_closed,Socket} ->  
  44.             io:format("Server socket closed~n")  
  45.     end.  

2. msg_test.erl

[plain] view plaincopy
  1. -module(msg_test).  
  2. -export([loop/0, send/1]).  
  3.   
  4. loop() ->  
  5.     receive  
  6.         {start_server, From} ->  
  7.             io:format("---start_server,from:~p~n", [From]),  
  8.             tcp_server:start_nano_server(From);  
  9.         {msg, D} ->  
  10.             io:format("---~p~n", [D]),  
  11.             loop();  
  12.         _Other ->  
  13.             loop()  
  14.     end.  
  15.   
  16. send(Pid) ->  
  17.     Pid ! {start_server, self()},  
  18.     receive  
  19.         {sock, Socket} ->  
  20.             io:format("---sock: ~p~n", [Socket]),  
  21.             io:format("---send remote socket: ~n"),  
  22.             Res = gen_tcp:send(Socket,term_to_binary("test remote socket")),  
  23.             io:format("---Result: ~p~n", [Res]);  
  24.         _Other ->  
  25.             error  
  26.     end.  
  27.       

运行测试截图:


 

上图中红圈旁的序号表示操作的先后步骤。

由测试结果可以得出最终结论:
1. 直接用远程Pid向这个进程发消息是可以的,形如:Remote_pid ! Msg,就能把Msg消息发送到其他节点的这个进程上;

2. 用gen_tcp:send(Remote_socket, Bin)向该Socket发数据是不行的,会返回{error, closed}错误;而gen_tcp:send(Local_socket, Bin)则是可以的,客户端会成功收到数据(见上图中的蓝色方框内容)。

阅读(1897) | 评论(0) | 转发(0) |
0

上一篇:进程与线程的区别

下一篇:应用宝sdk接入

给主人留下些什么吧!~~