Erlang-China

erlang 中文社区

【转】Erlang 中的 half-sync/half-async 和 Leader/Followers 模式


原文地址:avindev.javaeye.com
原文作者:AvinDev

http://www.javaeye.com/article/60414 里面,谈到了半同步/半异步和领导者/追随者模式,在Erlang里面可以很简单得实现它

下面看看 half-sync/half-async 的例子

代码
  1. start() ->
  2. case gen_tcp:listen(80, [binary,
  3. {nodelay,true},
  4. {packet, 0},
  5. {reuseaddr, true},
  6. {active, false}]) of
  7. {ok, Listen} ->
  8. io:format(“Listning port 80 @ ~p~n”, [self()]),
  9. accept_loop(Listen);
  10. Error -> io:format(“Error occur: ~p~n”, [Error])
  11. end.
  12. accept_loop(Listen) ->
  13. case gen_tcp:accept(Listen) of
  14. {ok, Socket} ->
  15. io:format(“Socket ~p connected~n”, [Socket]),
  16. spawn(?MODULE, handler, [Socket]),
  17. accept_loop(Listen);
  18. Other -> exit(oops)
  19. end.
  20. handler(Socket) ->
  21. io:format(“Waiting incoming message @ ~p~n”, [self()]),
  22. inet:setopts(Socket, [{nodelay,true}, {active, false}]),
  23. case gen_tcp:recv(Socket, 0) of
  24. {ok, Packet} ->
  25. io:format(“Receive msg ~p~n”, [binary_to_list(Packet)]),
  26. gen_tcp:send(Socket, Packet),
  27. gen_tcp:close(Socket),
  28. handler(Socket);
  29. {error, Reason} ->
  30. io:format(“Socket ~p error ~p~n”, [Socket, Reason])
  31. end.

在许多“网络编程”的教程里面,都会给出类似这样的例子。首先当前线程先监听一个端口,然后accept外来Socket连接,并将Socket传 递到新的线程中处理。在C、Java这样的语言中,创建一个线程的开销是很大的,一般来说,会使用线程池来处理短连接,一些Web Server就是基于这样的模式。然而在Erlang里面,创建一个Proces的开销极少,进程间切换完全在用户态实现,这样减少了用户态和核心态间切 换的开销,使得这种模式成为了可能。

接下来是Leader/Followers模式

代码
  1. start2() ->
  2. case gen_tcp:listen(81, [binary,
  3. {nodelay,true},
  4. {packet, 0},
  5. {reuseaddr, true},
  6. {active, false}]) of
  7. {ok, Listen} ->
  8. handler2(Listen);
  9. Error -> io:format(“Error occur: ~p~n”, [Error])
  10. end.
  11. handler2(Listen) ->
  12. io:format(“Listning port 81 @ ~p~n”, [self()]),
  13. case gen_tcp:accept(Listen) of
  14. {ok, Socket} ->
  15. io:format(“Socket ~p connected~n”, [Socket]),
  16. inet:setopts(Socket, [{nodelay,true}, {active, true}]),
  17. spawn(?MODULE, handler2, [Listen]),
  18. io:format(“Waiting incoming message @ ~p~n”, [self()]),
  19. receive
  20. {tcp, Socket, Bin} ->
  21. io:format(“Receive msg ~p~n”, [binary_to_list(Bin)]),
  22. gen_tcp:send(Socket, Bin),
  23. gen_tcp:close(Socket);
  24. {tcp_closed, Socket} ->
  25. io:format(“Socket ~p closed ~n”, [Socket]);
  26. Any ->
  27. io:format(“~p~n”, [Any])
  28. end;
  29. Other ->
  30. io:format(“~p~n”, [Other]),
  31. exit(oops)
  32. end.

当一个Socket连接建立后,就会将监听gen_tcp:accept/1的调用权转移到新的Process当中进行处理。

在这里,Leader Process 设置了这样一个参数
inet:setopts(Socket, [{nodelay,true}, {active, true}]),

在gen_tcp模块的文档中,有一段如下的说明

引用
Packets can be sent to the returned socket Socket using send/2. Packets sent from the peer are delivered as messages:
{tcp, Socket, Data}unless {active, false} was specified in the option list for the listen socket, in which case packets are retrieved by calling recv/2.

当在gen_tcp:listen/2中使用了{active, true}参数,那么当接收到数据的时候,就会主动发送消息到调用gen_tcp:accept/1的Process中,否则需要使用 gen_tcp:recv 来阻塞获取。通过这样的方式,就可以灵活实现同步/异步接收Socket数据。

Erlang网络编程还有其他有趣的地方,接下来的笔记我会写写这方面的内容。







Write a Comment

Note: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>