不解释,直接贴代码。
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实战这本书。