Skip to content
This repository has been archived by the owner on Oct 7, 2023. It is now read-only.

Non blocking server example

Pouriya Jahanbakhsh edited this page Jul 9, 2017 · 3 revisions

echo_server.erl:

-module(echo_server).
-behaviour(sockerl).

%% API:
-export([start/1
        ,packet_count/1]).


%% sockerl callbacks:
-export([listen_init/2
        ,connector_init/2
        ,handle_packet/3
        ,handle_disconnect/2
        ,handle_call/4
        ,terminate/3
        ,code_change/3]).





start(Port) ->
    RegisterName = {local, ?MODULE}, %% Optional
    CallbackMod = ?MODULE,
    InitArg = null,
    StartOpts = [],
    sockerl:start_link_server(RegisterName
                             ,CallbackMod
                             ,InitArg
                             ,Port
                             ,StartOpts).





packet_count(Con) ->
    gen_server:call(Con, how_much).





listen_init(null, _ListenSock) ->
    {ok, null2}.





%% In passive mode: 
%% When process is waiting for socket packet, it can't receive Erlang messages.
%% When process is waiting for Erlang message, it can't receive socket packets.
%% So i need to define timeout for Erlang receive and socket receive.
%% Use {'timeout', timeout()} for Erlang receive, after timeout if
%%  process did not get message, callback 'timeout/2' will be called.
%% Use {'srtimeout', timeout()} (SRTimeout: Socket Receive Timeout) for
%%  socket receive, after timeout if process did not get packet,
%%  callback 'srtimeout/2' will be called.
%% In passive mode if you want to read for example 4 bytes from socket,
%%  you can define {'length', positive_integer()} in return of every
%%  callback.
%% If you want to use your previous length, timeout or srtimeout value
%%  for increasing or decrasing, etc, dont put it in your state,
%%  Metadata has them.
%% #sockerl_metadata{socket = Sock
%%                  ,timeout = Timeout
%%                  ,srtimeout = SRTimeout
%%                  ,length = Len
%%                  ,transporter = TrMod
%%                  ,options = Opts}
%% Just use sockerl_metadata API..
connector_init(null2, _SMD) ->
    {ok, [{state, 0}]}.





handle_packet(Pkt, Count = _MyState, _SMD) ->
    {ok, [{state, Count + 1}, {packet, Pkt}]}.





handle_call(how_much, From, Count, _SMD) ->
    {ok, [{reply, From, Count}]}.





handle_disconnect(_Count, _SMD) ->
    %% If client closes connection, 
    %% Server connection process will crash with reason 'normal'
    {stop, normal}.





terminate(_Reason, _State, _SMD) ->
    ok.





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

Compile and go to the Erlang shell (You should add path for echo_server.beam and sockerl and its dependencies):

Erlang/OTP 19 [erts-8.2.2] [source-1ca84a4] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V8.2.2  (abort with ^G)
1> echo_server:start(8080).
{ok,<0.104.0>}

%% Getting all available server connections:
2> sockerl:get_server_connections(echo_server).
[]

Make a telnet connection to server:

$ telnet 127.0.0.1 8080

Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

Get server connections again:

3> sockerl:get_server_connections(echo_server).
[{#Port<0.7532>,<0.116.0>}]

Send some texts in telnet connection:

foo
foo
2
2
3
3
4
4
5
5

Server replies after sending every text.
Check packet count for connection:

%% Getting pid of our connection process
4> [{_, Con}] = sockerl:get_server_connections(echo_server).
[{#Port<0.7532>,<0.116.0>}]

5> echo_server:packet_count(Con).
5
Clone this wiki locally