`
coderplay
  • 浏览: 571870 次
  • 性别: Icon_minigender_1
  • 来自: 广州杭州
社区版块
存档分类
最新评论

tcp_server.erl注解

阅读更多
java 代码
 
  1. %% Copyright (C) 2002, Joe Armstrong  
  2. %% File    : tcp_server.erl  
  3. %% Author  : Joe Armstrong (joe@sics.se)  
  4. %% Purpose : Keeps track of a number of TCP sessions  
  5. %% Last modified: 2002-11-17  
  6.   
  7. -module(tcp_server).  
  8.   
  9. -export([start_raw_server/4, start_client/3,  
  10.      stop/1, children/1]).  
  11.   
  12. -define(KILL_DELAY, 1000).  
  13.   
  14. %% -export([start_child/3]).  
  15.   
  16. %% start_raw_server(Port, Fun, Max)  
  17. %%   This server accepts up to Max connections on Port  
  18. %%   The *first* time a connection is made to Port  
  19. %%   Then Fun(Socket) is called.   
  20. %%   Thereafter messages to the socket result in messsages to the handler.  
  21.   
  22. %% a typical server is usually written like this:  
  23.   
  24. %% To setup a lister  
  25.   
  26. %% start_server(Port) ->      
  27. %%     S = self(),  
  28. %%     process_flag(trap_exit, true),  
  29. %%     tcp_server:start_raw_server(Port,   
  30. %%              fun(Socket) -> input_handler(Socket, S) end,   
  31. %%              15,  
  32. %%                              0)  
  33. %%     loop().  
  34.   
  35. %% The loop() process is a central controller that all  
  36. %% processes can use to synchronize amongst themselfves if necessary  
  37. %% It ends up as the variable "Controller" in the input_handler  
  38.   
  39. %% A typical server is written like this:  
  40.   
  41. %% input_handler(Socket, Controller) ->  
  42. %%     receive  
  43. %%  {tcp, Socket, Bin} ->  
  44. %%      ...  
  45. %%      gen_tcp:send(Socket, ...)  
  46. %%   
  47. %%  {tcp_closed, Socket} ->  
  48. %%  
  49. %%   
  50. %%  Any ->  
  51. %%      ...  
  52. %%   
  53. %%     end.  
  54.   
  55. start_client(Host, Port, Length) ->  
  56.      gen_tcp:connect(Host, Port,  
  57.              [binary,   
  58.               {active, true},   
  59.               {packet, 2},  
  60.               {packet_size, Length}], 30000).  
  61.                        
  62. %% Note when start_raw_server returns, it should be ready to  
  63. %% Immediately accept connections  
  64. %% 作用  
  65. %%      当start_raw_server返回时, 就可以接受连接啦  
  66. %% 参数  
  67. %%      Port    服务器监听端口  
  68. %%      Fun     数据处理函数  
  69. %%      Max     最大连接数  
  70. %%      Length  最大包的长度
  71. start_raw_server(Port, Fun, Max, Length) ->  
  72.     Name = port_name(Port), % 用端口号来命名进程   
  73.     case whereis(Name) of  
  74.     undefined ->            % 如果端口还未定义的话,则启动  
  75.         Self = self(),  
  76.         Pid = spawn_link(fun() ->   % 产生一个新进程  
  77.                      cold_start(Self, Port, Fun, Max, Length)   % 冷启动  
  78.                  end),  
  79.         receive  
  80.         {Pid, ok} ->  
  81.             register(Name, Pid), % 接收到  
  82.             {ok, Pid};  
  83.         {Pid, Error} ->  
  84.             Error  
  85.         end;  
  86.     _Pid ->             % 如果端口已定义,则报错  
  87.         {error, already_started}  
  88.     end.  
  89.   
  90. stop(Port) when integer(Port) ->  
  91.     Name = port_name(Port),  
  92.     case whereis(Name) of  
  93.     undefined ->  
  94.         not_started;  
  95.     Pid ->  
  96.         exit(Pid, kill),  
  97.         (catch unregister(Name)),  
  98.         stopped  
  99.     end.  
  100.   
  101. children(Port) when integer(Port) ->  
  102.     port_name(Port) ! {children, self()},   %   
  103.     receive  
  104.     {session_server, Reply} -> Reply  
  105.     end.  
  106.   
  107. %% 作用  
  108. %%      以端口号做为服务名称  
  109. %% 参数  
  110. %%      端口号  
  111. port_name(Port) when integer(Port) ->  
  112.     list_to_atom("portServer" ++ integer_to_list(Port)).  
  113.   
  114. %% 作用  
  115. %%      启动服务  
  116. %%  参数  
  117. %%      Master      所有者  
  118. %%      Port        端口  
  119. %%      Fun         处理函数  
  120. %%      Max         数大连接数  
  121. %%      Length      最大包的长度
  122. cold_start(Master, Port, Fun, Max, Length) ->  
  123.     process_flag(trap_exit, true),  % 设置退出陷阱  
  124.     io:format("Starting a port server on ~p...~n",[Port]),  
  125.     % 绑定到端口,进行监听  
  126.     case gen_tcp:listen(Port, [binary,  
  127.                    %% {dontroute, true},  
  128.                    {nodelay,true},  
  129.                    {packet_size, Length},  
  130.                    {packet, 2},  
  131.                    {backlog, 1024},  
  132.                    {reuseaddr, true},   
  133.                    {active, false}]) of  
  134.     {ok, Listen} ->  
  135.         %% io:format("Listening on:~p~n",[Listen]),  
  136.         Master ! {self(), ok},  % 发送成功消息  
  137.         New = start_accept(Listen, Fun), % 开始接受连接   
  138.         %% Now we're ready to run  
  139.         socket_loop(Listen, New, [], Fun, Max); % 接受连接后,开始网络通信了   
  140.     Error ->  
  141.         Master ! {self(), Error}  
  142.     end.  
  143.   
  144. %% Don't mess with the following code uless you really know what you're   
  145. %% doing (and Thanks to Magnus for heping me get it right)  
  146. %% 作用  
  147. %%      接受连接后,开始运作  
  148. socket_loop(Listen, New, Active, Fun, Max) ->  
  149.     receive  
  150.     {istarted, New} ->  
  151.         Active1 = [New|Active], % 参见start_child,把新连接加入到活动列表中  
  152.         possibly_start_another(false, Listen, Active1, Fun, Max);  
  153.     {'EXIT', New, _Why} ->  
  154.         %%io:format("Child exit=~p~n",[Why]),  
  155.         possibly_start_another(false, Listen, Active, Fun, Max);  
  156.     {'EXIT', Pid, _Why} ->  
  157.         %%io:format("Child exit=~p~n",[Why]),  
  158.         Active1 = lists:delete(Pid, Active),  
  159.         possibly_start_another(New, Listen, Active1, Fun, Max);  
  160.     {children, From} ->  
  161.         From ! {session_server, Active},  
  162.         socket_loop(Listen, New, Active, Fun, Max);  
  163.     Other ->  
  164.         io:format("Here in loop:~p~n",[Other])  
  165.     end.  
  166.   
  167. possibly_start_another(New, Listen, Active, Fun, Max) when pid(New) ->  
  168.     socket_loop(Listen, New, Active, Fun, Mzax);  
  169. possibly_start_another(false, Listen, Active, Fun, Max) ->  
  170.     case length(Active) of  
  171.     N when N < Max ->  
  172.         New = start_accept(Listen, Fun),  
  173.         socket_loop(Listen, New, Active, Fun, Max);  
  174.     _ ->  
  175.         error_logger:warning_report(  
  176.           [{module, ?MODULE},  
  177.            {line, ?LINE},  
  178.            {message, "Connections maxed out"},  
  179.            {maximum, Max},  
  180.            {connected, length(Active)},  
  181.            {now, now()}]),  
  182.         socket_loop(Listen, false, Active, Fun, Max)  
  183.     end.  
  184.   
  185. %% 作用  
  186. %%      开始接受连接啦  
  187. %% 参数  
  188. %%      Listen  监听的Socket  
  189. %%      Fun     数据处理函数  
  190. start_accept(Listen, Fun) ->  
  191.     S = self(),  
  192.     spawn_link(fun() -> start_child(S, Listen, Fun) end). % 一个进程处理一个连接  
  193.   
  194. start_child(Parent, Listen, Fun) ->  
  195.     case gen_tcp:accept(Listen) of  % 接受一个连接  
  196.     {ok, Socket} ->  
  197.         Parent ! {istarted,self()}, % 参见socket_loop, tell the controller  
  198.         inet:setopts(Socket, [{nodelay,true},  
  199.                   {packet, 2},  
  200.                   {active, true}]), % before we activate socket  
  201.         Fun(Socket); % 这里应用了数据处理函数Fun  
  202.     _Other ->  
  203.         exit(oops)  
  204.     end.  
  205.   
  206.           
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics