erlang高性能网络库esockd的编译和使用(二)-application

真正项目开发使用还是需要自己写app程序,把esockd作为第三方的依赖库使用。

一、前期准备

1、新建文件夹myerlserver

然后输入终端命令

./rebar create-app appid=myerlserver

./rebar create template=simplesrv srvid=start_server

./rebar create template=simplesrv srvid=echo_server
手动新建rel文件夹
../rebar create-node nodeid=myerlserver

2、rebar.config文件修改为:

{deps, [
{esockd, ".*", {git, "git://github.com/emqtt/esockd.git", {tag, "v4.2"}}}
]}.

{sub_dirs, ["rel"]}.

其中“v4.2”来自https://github.com/emqtt/esockd里面定义的Tags字符串,可以是“4.0”,“v4.1”和“v4.2”等等关键字。

3、reltool.config文件修改为:

%% -*- mode: erlang -*-
%% ex: ft=erlang
{sys, [
       {lib_dirs, ["../deps"]},
       {erts, [{mod_cond, derived}, {app_file, strip}]},
       {app_file, strip},
       {rel, "myerlserver", "1",
        [
         kernel,
         stdlib,
         sasl,
         goldrush,
         lager,
         gen_logger,
         esockd,
         myerlserver
        ]},
       {rel, "start_clean", "",
        [
         kernel,
         stdlib
        ]},
       {boot_rel, "myerlserver"},
       {profile, embedded},
       {incl_cond, derived},
       {excl_archive_filters, [".*"]}, %% Do not archive built libs
       {excl_sys_filters, ["^bin/(?!start_clean.boot)",
                           "^erts.*/bin/(dialyzer|typer)",
                           "^erts.*/(doc|info|include|lib|man|src)"]},
       {excl_app_filters, ["\.gitignore"]},
       {app, myerlserver, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]}
      ]}.

{target_dir, "myerlserver"}.

{overlay, [
           {mkdir, "log/sasl"},
           {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
           {copy, "files/nodetool", "releases/\{\{rel_vsn\}\}/nodetool"},
           {copy, "myerlserver/bin/start_clean.boot",
                  "\{\{erts_vsn\}\}/bin/start_clean.boot"},
           {copy, "files/myerlserver", "bin/myerlserver"},
           {copy, "files/myerlserver.cmd", "bin/myerlserver.cmd"},
           {copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
           %% Following line may be safely removed in new projects
           {copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
           {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
           {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
          ]}.


4、终端输入命令获得依赖库:

./rebar get-deps


二、源文件

myerlserver_sup.erl

-module(myerlserver_sup).

-behaviour(supervisor).

%% API
-export([start_link/0]).

%% Supervisor callbacks
-export([init/1]).

%% Helper macro for declaring children of supervisor
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).

%% ===================================================================
%% API functions
%% ===================================================================

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

%% ===================================================================
%% Supervisor callbacks
%% ===================================================================

init([]) ->
    {ok, { {one_for_one, 5, 10}, [?CHILD(start_server, worker)]} }.

start_server.erl

-module(start_server).
-behaviour(gen_server).
-define(SERVER, ?MODULE).

%% ------------------------------------------------------------------
%% API Function Exports
%% ------------------------------------------------------------------

-export([start_link/0]).

%% ------------------------------------------------------------------
%% gen_server Function Exports
%% ------------------------------------------------------------------

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

%% ------------------------------------------------------------------
%% API Function Definitions
%% ------------------------------------------------------------------

start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%% ------------------------------------------------------------------
%% gen_server Function Definitions
%% ------------------------------------------------------------------

init(Args) ->
    echo_server:start(),
    {ok, Args}.

handle_call(_Request, _From, State) ->
    {reply, ok, State}.

handle_cast(_Msg, State) ->
    {noreply, State}.

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

terminate(_Reason, _State) ->
    ok.

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

%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------

echo_server.erl

-module(echo_server).

-include("../deps/esockd/include/esockd.hrl").

-behaviour(gen_server).

%% start
-export([start/0, start/1]).
-export([start_link/1]).

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

-record(state, {conn}).

-define(TCP_OPTIONS, [
	binary,
        {packet, raw},
        {buffer, 1024},
	{reuseaddr, true},
	{backlog, 512},
	{nodelay, false}]).

-define(TCP_PORT, 5000).

%% API
start() ->
    start(?TCP_PORT).

start([Port]) when is_atom(Port) ->
    start(list_to_integer(atom_to_list(Port)));

start(Port) when is_integer(Port) ->
    %% application:start(sasl),
    %% ok = esockd:start(),
    Access = application:get_env(esockd, access, [{allow, all}]),
    SockOpts = [{access, Access},
                {acceptors, 32},
                {max_clients, 1000000},
                {sockopts, ?TCP_OPTIONS}],
    MFArgs = {?MODULE, start_link, []},
    esockd:open(echo, Port, SockOpts, MFArgs).

%% eSockd Callbacks
start_link(Conn) ->
    {ok, proc_lib:spawn_link(?MODULE, init, [Conn])}.

init(Conn) ->
    {ok, Conn1} = Conn:wait(),
    Conn1:setopts([{active, once}]),
    gen_server:enter_loop(?MODULE, [], #state{conn = Conn1}).

handle_call(_Request, _From, State) ->
    {reply, ok, State}.

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({tcp, Sock, Data}, State = #state{conn = ?ESOCK(Sock) = Conn}) ->
    {ok, PeerName} = Conn:peername(),
    io:format("~s - ~s~n", [esockd_net:format(peername, PeerName), Data]),
    Conn:send(Data),
    Conn:setopts([{active, once}]),
    {noreply, State};

handle_info({tcp_error, Sock, Reason}, State = #state{conn = ?ESOCK(Sock)}) ->
    io:format("tcp_error: ~s~n", [Reason]),
    {stop, {shutdown, {tcp_error, Reason}}, State};

handle_info({tcp_closed, Sock}, State = #state{conn = ?ESOCK(Sock)}) ->
    io:format("tcp_closed~n"),
    {stop, normal, State};

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

terminate(_Reason, _State) ->
    ok.

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

Gen_server行为分析与实践

enter_loop(Module, Options, State)
enter_loop(Module, Options, State, ServerName)
enter_loop(Module, Options, State, Timeout)
enter_loop(Module, Options, State, ServerName, Timeout)
Options = [Option]
Option = {debug,Dbgs}
Dbgs = [trace | log | statistics | {log_to_file,FileName} | {install,{FuncState}}]
ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
Timeout = int() | infinity
该函数的功能是让一个已经存在的进程成为gen_server进程,通过请求进程让它进入gen_server循环成为gen_server进程,该普通进程的创建必须通过proc_lib模块(实例3.4)。
这个函数更加的有用对于要进行比gen_server还要复杂的初始化时。
Module, Options and ServerName 的意义与gen_server:start_link一样.然而,如果Servername被指定这个进程被调用前一定要相应的先注册。
State and Timeout与回调函数的Module:init一样。

Failure: 如果请求进程不是一个由proc_lib创建的进程或使用了没有注册的ServerName.


Module:init(Args) -> Result
Types:
Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate}| {stop,Reason} | ignore
State = term()
Timeout = int()>=0 | infinity
通过start或start_link初始化一个新的进程。
若初始化成功返回{ok,State} | {ok,State,Timeout} | {ok,State,hibernate}。State是gen_server的内部状态;Timeout指进程初始化后等待接受请求的时间限制,超过时间限制将向handle_info发送请求为timeout的信息,默认是infinity;hibernate指可通过调用proc_lib:hibernate/3使进程进入冬眠状态从而进行GC,当有消息请求该进程,处理该请求,然后冬眠并进行GC.注意应该小心使用'hibernate',主要针对空闲时间比较长的进程,因为至少有两个GC回收器,对于请求比较平凡的进程,资源的消耗高。
如果初始化失败将返回{stop,Reason} | ignore


注解:并不是简单的通过spawn在子进程启动函数中启动一个进程然后返回{ok, Pid}就可以让子进程拥有出错自动重启的功能。实际上,需要使用proc_lib:spawn_link或者proc_lib:start_link启动子进程,才能在子进程出错退出时让supervisor自动重启它。proc_lib:start_link和proc_lib:spawn_link的不同之处在于,前者是同步创建子进程,后者是异步创建子进程,proc_lib:start_link调用后会阻塞,直到子进程初始化完毕,调用proc_lib:init_ack后才返回。而proc_lib:spawn_link一调用就会立即返回子进程ID。



三、编译和发布
./rebar compile
./rebar generate
ulimit -n 100000
./myerlserver console

其实也可以把几个命令联合一起执行,例如:

./rebar clean compile generate

./rebar compile generate


本文rebar的使用参考了文章:用 rebar 来构建、编译、测试、发布 Erlang 应用程序

完整的工程源码请访问:http://download.csdn.net/download/libaineu2004/10048006


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值