不解释,直接贴代码。
1) socket_options.hrl
-record(socket_options, {port=8024, loop, name, ip=any, nodelay=false, backlog=128, listen=null, active_sockets=0} ).
2) test_server.erl
-module(test_server). -export([start/0, stop/0, looper/1]). -include("socket_options.hrl"). %开启服务 start()-> test_socket_server:start(#socket_options{loop = {?MODULE, looper}}). %关闭服务 stop()-> test_socket_server:stop(). looper(Socket) -> inet:setopts(Socket, [{active, once}]), receive {tcp, Socket, Data} -> io:format("Got packet: ~p~n", [Data]), gen_tcp:send(Socket, Data), looper(Socket); {tcp_closed, Socket}-> io:format("Socket ~p closed~n", [Socket]); {tcp_error, Socket, Reason} -> io:format("Error on socket ~p reason: ~p~n", [Socket, Reason]) end.
3) test_socket_server.erl
-module(test_socket_server). -export([start/0, start/1, stop/0, stop/1]). -export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3, handle_info/2]). -include("socket_options.hrl"). -define(RECBUF_SIZE, 8192). start() -> gen_server:start(?MODULE, [], []). start(InitArg = #socket_options{name = Name}) -> case Name of undefined -> gen_server:start({local,?MODULE}, ?MODULE, InitArg, []); _ -> gen_server:start({local,Name}, ?MODULE, InitArg, []) end. stop() -> gen_server:cast(?MODULE, stop). stop(Name) when is_atom(Name) -> gen_server:cast(Name, stop); stop(Pid) when is_pid(Pid) -> gen_server:cast(Pid, stop); stop(_State = #socket_options{name = Name}) -> stop(Name). %回调函数 %init(State = #socket_options{ip = Ip, port = Port, backlog = Backlog, nodelay = NoDelay}) -> init(State = #socket_options{port = Port, backlog = Backlog, nodelay = NoDelay}) -> BaseOpts = [binary, {reuseaddr, true}, {packet, 0}, {backlog, Backlog}, {recbuf, ?RECBUF_SIZE}, {active, false}, {nodelay, NoDelay}], listen(Port, BaseOpts, State). %%监听 handle_call(_Msg, _Caller, State) -> {noreply, State}. handle_info(_Msg, Library) -> {noreply, Library}. terminate(Reason, #socket_options{listen = Listen}) -> io:format("socket close,~p~n",[Reason]), gen_tcp:close(Listen). %%关闭Listen code_change(_OldVsn, State, _Extra) -> State. handle_cast({accepted, _Pid}, State = #socket_options{active_sockets = ActiveSockets, listen = Listen, loop = Loop}) -> NewState = State#socket_options{active_sockets = 1 + ActiveSockets}, test_socket_server_acceptor:start_link(self(), Listen, Loop), {noreply, NewState}; handle_cast(stop, Name) -> %io:format("关闭服务器!~n"), {stop, normal , Name}. listen(Port, Opts, State) -> case gen_tcp:listen(Port, Opts) of {ok, Listen} -> test_socket_server_acceptor:start_link(self(), Listen, State#socket_options.loop), NewState = State#socket_options{listen = Listen}, {ok, NewState}; {error, Reason} -> {stop, Reason} end.
4) test_socket_server_acceptor.erl
-module(test_socket_server_acceptor). -export([start_link/3, init/3]). start_link(Server, Listen, Loop) -> proc_lib:spawn_link(?MODULE, init, [Server, Listen, Loop]). init(Server, Listen, Loop) -> case catch gen_tcp:accept(Listen) of {ok, Socket} -> gen_server:cast(Server, {accepted, self()}), call_loop(Loop, Socket); {error, closed} -> exit(normal); {error, timeout} -> init(Server, Listen, Loop); {error, esslaccept} -> exit(normal); _ -> exit({error, accept_failed}) end. call_loop({M, F}, Socket) -> io:format("socket call_loop,~n"), M:F(Socket); call_loop({M, F, [A1]}, Socket) -> M:F(Socket, A1); call_loop({M, F, A}, Socket) -> erlang:apply(M, F, [Socket | A]); call_loop(Loop, Socket) -> Loop(Socket).
下一步是想在此基础上写一个聊天室什么的,不过我目前我想先实践完OTP实战这本书。