其实也不能算是我的了,是我去年从mochiweb里扣出来的最最最基本的TCP通信代码, mochiweb是一个开源的高并发HTTP服务器,据说可以打造百万级应用。 mochiweb 有上万行,我抠出来只有百多行,算是够精简的了,现在贴出来,方便像我一样的菜鸟学习,造福人类。其实也是方便我自己,放硬盘上估计过段时间就找不到了。很久没有看这语言了,改不动,所以特别感谢北京-CS帮我修改了错误。

  功能很简单,就是收到什么数据,就发送什么数据,可以作为很好的入门代码,就不解释那么多了,直接贴代码:

my_server模块如下:

 
  
  1. -module(my_server). 
  2. -export([start/0, stop/0, looper/1]). 
  3.  
  4.  %这个Options我本来打算从配置文件里读取,然后组装成一个record,但是不大熟,所以这里没有用到它
  5. %以后用得上再改
  6. -define(Options, [ 
  7.             {port, 8442}, 
  8.             {loop, {?MODULE, loop}}, 
  9.             {name, ?MODULE} 
  10.             ]). 
  11.              
  12.  -record(qiao_socket_server, 
  13.         {port=8024,                        
  14.          loop,                 
  15.          name,               
  16.          ip=any,                      
  17.          nodelay=false
  18.          backlog=128, 
  19.          listen=null,                 
  20.          active_sockets=0}             
  21.         ). 
  22.              
  23. start() -> 
  24.     %%socket_server:start(?Options). 
  25.     socket_server:start(#qiao_socket_server{loop = {?MODULE, looper}}).  
  26.  
  27. stop() -> 
  28.     socket_server:stop(?Options). 
  29. %关闭服务的我也没有改,所以这里有个错误。     
  30. looper(Socket) -> 
  31.     inet:setopts(Socket, [{active, once}]), 
  32.     receive 
  33.     {tcp, Socket, Data} -> 
  34.         io:format("Got packet: ~p~n", [Data]),  %接收到什么数据,就发生什么数据
  35.         gen_tcp:send(Socket, Data), 
  36.         looper(Socket); 
  37.     {tcp_closed, Socket}-> 
  38.         io:format("Socket ~p closed~n", [Socket]); 
  39.     {tcp_error, Socket, Reason} -> 
  40.         io:format("Error on socket ~p reason: ~p~n", [Socket, Reason]) 
  41.     end. 

 socket_server模块代码如下:

 

 
  
  1. -module(socket_server). 
  2. -author('huanghongqiao'). 
  3. -behaviour(gen_server). 
  4.   
  5. -export([start/0,start/1, stop/1]). 
  6. -export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3, 
  7.          handle_info/2]). 
  8.   
  9.   
  10.  -define(RECBUF_SIZE, 8192). 
  11.  
  12.  -record(qiao_socket_server, 
  13.         {port=8024,                        
  14.          loop,                 
  15.          name,               
  16.          ip=any,                      
  17.          nodelay=false
  18.          backlog=128, 
  19.          listen=null,                 
  20.          active_sockets=0}             
  21.         ). 
  22. %%客户端函数, start 开启服务,stop 关闭服务 
  23. start() -> 
  24.     gen_server:start(?MODULE, [], []). 
  25. start(InitArg = #qiao_socket_server{name = Name}) -> 
  26.     case Name of 
  27.         undefined -> 
  28.         gen_server:start(?MODULE, InitArg, []); 
  29.         _ -> 
  30.             gen_server:start(Name, ?MODULE, InitArg, []) 
  31.     end. 
  32.     
  33. stop(Name) when is_atom(Name) -> 
  34.     gen_server:cast(Name, stop); 
  35. stop(Pid) when is_pid(Pid) -> 
  36.     gen_server:cast(Pid, stop); 
  37. stop(State = #qiao_socket_server{name = Name}) -> 
  38.     stop(Name). 
  39.   
  40.   
  41. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
  42.                  %% 回调函数  
  43. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  44. init(State = #qiao_socket_server{ip=Ip, port=Port, backlog=Backlog, nodelay=NoDelay}) -> 
  45.     BaseOpts = [binary, 
  46.         {reuseaddr, true}, 
  47.         {packet, 0}, 
  48.         {backlog, Backlog}, 
  49.         {recbuf, ?RECBUF_SIZE}, 
  50.         {active, false}, 
  51.         {nodelay, NoDelay}], 
  52.     listen(Port, BaseOpts, State).    %%监听         
  53.   
  54. handle_call(_Msg, _Caller, State) -> {noreply, State}. 
  55.      
  56. handle_info(_Msg, Library) -> {noreply, Library}. 
  57.  
  58. terminate(Reason, #qiao_socket_server{listen=Listen}) -> 
  59.     io:format("socket close,~p~n",[Reason]), 
  60.     gen_tcp:close(Listen).             %%关闭Listen 
  61.  
  62. code_change(_OldVsn, State, _Extra) -> 
  63.     State. 
  64.  
  65. handle_cast({accepted, Pid}, State=#qiao_socket_server{active_sockets=ActiveSockets,  
  66.             listen = Listen, loop = Loop}) -> 
  67.     NewState = State#qiao_socket_server{active_sockets=1 + ActiveSockets}, 
  68.     socket_server_acceptor:start_link(self(), Listen, Loop), 
  69.     {noreply, NewState}. 
  70.  
  71.  
  72. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  73.  
  74. listen(Port, Opts, State) -> 
  75.     case gen_tcp:listen(Port, Opts) of 
  76.         {ok, Listen} -> 
  77.             socket_server_acceptor:start_link(self(), Listen, State#qiao_socket_server.loop), 
  78.             NewState = State#qiao_socket_server{listen = Listen}, 
  79.             {ok, NewState}; 
  80.         {error, Reason} -> 
  81.             {stop, Reason} 
  82.     end. 
  83.   

socket_server_acceptor模块代码如下:

 

 
  
  1. -module(socket_server_acceptor). 
  2. -export([start_link/3, init/3]). 
  3.  
  4. start_link(Server, Listen, Loop) -> 
  5.     proc_lib:spawn_link(?MODULE, init, [Server, Listen, Loop]). 
  6.  
  7. init(Server, Listen, Loop) -> 
  8.     case catch gen_tcp:accept(Listen) of 
  9.         {ok, Socket} -> 
  10.             gen_server:cast(Server, {accepted, self()}), 
  11.         io:format("socket init,~p~n", [self()]), 
  12.             call_loop(Loop, Socket); 
  13.         {error, closed} -> 
  14.         io:format("socket close,~n"), 
  15.             exit(normal); 
  16.         {error, timeout} -> 
  17.         io:format("socket timeout"), 
  18.             init(Server, Listen, Loop); 
  19.         {error, esslaccept} -> 
  20.         io:format("socket close2,~n"), 
  21.             exit(normal); 
  22.         R -> 
  23.         io:format("socket close1,~p~n",[R]), 
  24.             exit({error, accept_failed}) 
  25.     end. 
  26.  
  27. call_loop({M, F}, Socket) -> 
  28.     io:format("socket call_loop,~n"), 
  29.     M:F(Socket); 
  30. call_loop({M, F, [A1]}, Socket) -> 
  31.     M:F(Socket, A1); 
  32. call_loop({M, F, A}, Socket) -> 
  33.     erlang:apply(M, F, [Socket | A]); 
  34. call_loop(Loop, Socket) -> 
  35.     Loop(Socket). 

运行效果见下图,具体能支持多少并发,我也没有测试过,哈哈: