Source

hello / erlang / tcp_base_server.erl

Full commit
-module(tcp_base_server).
-behaviour(gen_server).

-compile( export_all ).
-author('kuenishi@gmail.com').

-import(gen_tcp).

% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
	 terminate/2, code_change/3]).

% interfaces for gen_server
-export([start_listen/2, start_accepts/3, server/2, session_handler/2]).

% interfaces for users
-export([start/0, stop/0]).

% こんな幹事で実行:
% $ erl  +A 16 -smp +K true
%
-define(NUM_WORKERS, 5).
-define(DEFAULT_PORT, 3000).

%% TCP options for our listening socket.  The initial list atom
%% specifies that we should receive data as lists of bytes (ie
%% strings) rather than binary objects and the rest are explained
%% better in the Erlang docs than I can do here.
-define(TCP_OPTIONS,[list, {packet, 0}, {active, false}, {reuseaddr, true}]).


% interfaces
start()->  gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
stop()->   gen_server:call(?MODULE, stop).


% callbacks
init([])->
%    process_flag(trap_exit, true),
    FS = ets:new( filesystem, [set]),
    ets:insert(FS, {"/usr/local/hoge", "aaaaa"}),
    ets:insert(FS, {"/usr/local/huga", "aaaa"}),
    ets:insert(FS, {"/usr/local",      "aaa"}),
    ets:insert(FS, {"/aasfd","bbb"}),
    io:format("~p starting...", [?MODULE]),
    Processes=start_listen(?DEFAULT_PORT, FS),
    io:format("port: ~p ~n", [?DEFAULT_PORT]),
    {ok,[FS|Processes]}.

start_listen(LPort, FS) ->
    case gen_tcp:listen(LPort,[{active, true},{packet,2}]) of
        {ok, ListenSock} ->
            {ok, start_accepts(?NUM_WORKERS, ListenSock, FS) };%   {ok, Port} = inet:port(ListenSock),
        {error,Reason} ->
	    io:format("~p@~p~n", [Reason, self()]),
	    exit(Reason)
    end.

start_accepts(0,_,_) ->  [];
start_accepts(Num,LS, FS) ->
%    io:format("before spawn~p~n", [Num]),
    P=spawn(?MODULE, server,[LS, FS]),
%    register(Num, P),
%    io:format("after spawn~p~n",[Num]),
    [ P | start_accepts(Num-1,LS, FS)].  %//    [Processes|P].
                       
server(LS, FS) ->
    io:format("start accepting...~n"),
    case gen_tcp:accept(LS) of
        {ok,S} ->
            spawn_link( fun()->session_handler(S, FS) end),
            server(LS, FS);
	{error, closed} -> ok;
        Other ->
            io:format("accept returned ~w - goodbye!~n",[Other]),
            ok
    end.

% client に対する処理
session_handler(S, FS) ->
    inet:setopts(S,[{active,once}]),
    receive
        {tcp,S,Data} ->
	    io:format("~p~n",[Data]),
            Answer = process(Data, FS), % Not implemented in this example
	    io:format("~p~n",[Answer]),
            gen_tcp:send(S,Answer),
            session_handler(S,FS);
        {tcp_closed,S} ->
            io:format("Socket ~w closed [~w]~n",[S,self()]),
            ok
    end.

process(Data, FS)->
    Code = list_to_integer( string:substr(Data, 0, 2) ),
    Seed = string:substr(Data, 3),
    case Code of
	100 -> Ret = [integer_to_list(200)|Seed],
	       Ret
	end.
    
    %[{Key, Value}|_] = ets:lookup( FS, Data ),
    %io:format("~p <- ~p.~n", [Value, Key]),
    %Value.

handle_call(_, From, [FS|_])->
    {noreply, From, FS}.

handle_cast(stop, State)->
    {stop, normal, State};
handle_cast(Msg, State)->
    {noreply, Msg, State}.

handle_info(Info, State)->
    {noreply, Info, State}.

terminate(Reason, State)->
    io:format("terminating...~p.~n", [Reason]),
    {ok, State, Reason}.

code_change(_OldVsn, State, Extra)->
    {ok, State, Extra}.