Skip to content

Commit

Permalink
Merge pull request #18 from emqtt/esockd3
Browse files Browse the repository at this point in the history
eSockd3
  • Loading branch information
Feng Lee committed Nov 4, 2015
2 parents 28908e4 + 987d9ac commit 9be95f2
Show file tree
Hide file tree
Showing 27 changed files with 513 additions and 228 deletions.
9 changes: 9 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
language: erlang

otp_release:
- 17.0

script:
- make

sudo: false
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
eSockd ChangeLog
==================

3.0-beta (2015/10/30)
------------------------

Parameterized Connection Module

Rate Limit


2.8.0-beta (2015/10/28)
------------------------

Expand Down
74 changes: 37 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@

# eSockd
# eSockd [![Build Status](https://travis-ci.org/emqtt/esockd.svg?branch=3.0)](https://travis-ci.org/emqtt/esockd)

Erlang General Non-blocking TCP/SSL Socket Server.

## Features

General Non-blocking TCP/SSL Socket Server.

Acceptor Pool and Asynchronous TCP Accept.

Max connections management.

Allow/Deny by peer address.

Keepalive Support.

## Benchmark

Benchmark 2.1.0-alpha release on one 8 cores, 32G memory ubuntu/14.04 server from qingcloud.com:

```
250K concurrent connections, 50K messages/sec, 40Mbps In/Out consumed 5G memory, 20% CPU/core
```
* General Non-blocking TCP/SSL Socket Server
* Acceptor Pool and Asynchronous TCP Accept
* Parameterized Connection Module
* Max connections management
* Allow/Deny by peer address
* Keepalive Support
* Rate Limit

## Usage

Expand All @@ -32,24 +22,24 @@ A Simple Echo Server:

-export([start_link/1]).

start_link(SockArgs) ->
{ok, spawn_link(?MODULE, init, [SockArgs])}.
start_link(Conn) ->
{ok, spawn_link(?MODULE, init, [Conn])}.

init(SockArgs = {Transport, _Sock, _SockFun}) ->
{ok, NewSock} = esockd_connection:accept(SockArgs),
loop(Transport, NewSock, state).

loop(Transport, Sock, State) ->
case Transport:recv(Sock, 0) of
{ok, Data} ->
{ok, Name} = Transport:peername(Sock),
io:format("~p: ~s~n", [Name, Data]),
Transport:send(Sock, Data),
loop(Transport, Sock, State);
{error, Reason} ->
io:format("tcp ~s~n", [Reason]),
{stop, Reason}
end.
init(Conn) ->
{ok, NewConn} = Conn:wait(),
loop(NewConn).

loop(Conn) ->
case Conn:recv(0) of
{ok, Data} ->
{ok, PeerName} = Conn:peername(),
io:format("~s - ~s~n", [esockd_net:format(peername, PeerName), Data]),
Conn:send(Data),
loop(Conn);
{error, Reason} ->
io:format("tcp ~s~n", [Reason]),
{stop, Reason}
end.
```

Startup Echo Server:
Expand Down Expand Up @@ -81,7 +71,7 @@ examples/

Example | Description
----------|------
async_recv| prim_net async recv
async_recv| prim_net async recv/send
gen_server| gen_server behaviour
simple | simple echo server
ssl | ssl echo server
Expand Down Expand Up @@ -122,6 +112,7 @@ Options:
{access, [esockd_access:rule()]} |
{logger, atom() | {atom(), atom()}} |
{ssl, [ssl:ssloption()]} |
{connopts, [{rate_limit, string()}]} |
{sockopts, [gen_tcp:listen_option()]}.
```

Expand Down Expand Up @@ -212,11 +203,20 @@ Logger option:
esockd:open(echo, 5000, [{logger, {error_logger, info}}], {echo_server, start_link, []}).
```

## Benchmark

Benchmark 2.1.0-alpha release on one 8 cores, 32G memory ubuntu/14.04 server from qingcloud.com:

```
250K concurrent connections, 50K messages/sec, 40Mbps In/Out consumed 5G memory, 20% CPU/core
```

## License

The MIT License (MIT)

## Author

[email protected]
Feng Lee <[email protected]>


17 changes: 0 additions & 17 deletions doc/connection_sup.md

This file was deleted.

3 changes: 0 additions & 3 deletions doc/keepalive.md

This file was deleted.

6 changes: 3 additions & 3 deletions doc/supervisor.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ esockd_sup
-> esockd_acceptor
-> esockd_acceptor
-> ......
-> esockd_client_sup
-> esockd_client
-> esockd_client
-> esockd_connection_sup
-> esockd_connection
-> esockd_connection
-> ......
```
Expand Down
17 changes: 17 additions & 0 deletions examples/async_recv/crt/demo.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICuTCCAiICCQC8+3PPaqATfDANBgkqhkiG9w0BAQUFADCBoDELMAkGA1UEBhMC
Q0gxETAPBgNVBAgTCFpoZUppYW5nMREwDwYDVQQHEwhIYW5nWmhvdTEUMBIGA1UE
ChMLWGlhb0xpIFRlY2gxHzAdBgNVBAsTFkluZm9ybWF0aW9uIFRlY2hub2xvZ3kx
EzARBgNVBAMTCnQuZW1xdHQuaW8xHzAdBgkqhkiG9w0BCQEWEGZlbmcgYXQgZW1x
dHQuaW8wHhcNMTUwMjI1MTc0NjQwWhcNMTYwMjI1MTc0NjQwWjCBoDELMAkGA1UE
BhMCQ0gxETAPBgNVBAgTCFpoZUppYW5nMREwDwYDVQQHEwhIYW5nWmhvdTEUMBIG
A1UEChMLWGlhb0xpIFRlY2gxHzAdBgNVBAsTFkluZm9ybWF0aW9uIFRlY2hub2xv
Z3kxEzARBgNVBAMTCnQuZW1xdHQuaW8xHzAdBgkqhkiG9w0BCQEWEGZlbmcgYXQg
ZW1xdHQuaW8wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALAtN2OHsvltOk+9
AtlwMtKuaWW2WpV/S0lRRG9x9k8pyd5PJeeYAr2jVsoWnZInb1CoEOHFcwxZLjv3
gEvz+X+//W02YyI9hnvCJUpT/+6P0gJEbmTmqL078M6vbtwtiF1YC7mdo0nGAZuK
qedpIoEZbVJavf4S0vXWTsb3s5unAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAgUR3
z4uDUsAl+xUorPMBIOS/ncHHVk1XucVv9Wi4chzzZ+4/Y77/fFqP6oxhQ59C9Q8i
iT5wjaE4R1eCge18lPSw3yb1tsTe5B3WkRTzziPq/Q/AsC+DifkkE1YW67leuJV/
vz74sEi0dudmOVoe6peYxjEH8xXoIUqhnwXt/4Q=
-----END CERTIFICATE-----
15 changes: 15 additions & 0 deletions examples/async_recv/crt/demo.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCwLTdjh7L5bTpPvQLZcDLSrmlltlqVf0tJUURvcfZPKcneTyXn
mAK9o1bKFp2SJ29QqBDhxXMMWS4794BL8/l/v/1tNmMiPYZ7wiVKU//uj9ICRG5k
5qi9O/DOr27cLYhdWAu5naNJxgGbiqnnaSKBGW1SWr3+EtL11k7G97ObpwIDAQAB
AoGBAKU1cbiLG0GdtU3rME3ZUj+RQNMZ4u5IVcBmTie4FcN8q4ombKQ2P3O4RX3z
IUZaZp+bS2F8uHt+8cVYPl57Zp5fwbIlv6jWgGpvXLsX8JBQl2OTw38B+hVwJvAM
h0mBzprUOs3KGZyF5cyA4osrZ4QvCZhwId9fAjwLGBF9i1yBAkEA4jWAF1sWQiwF
vY476m+0ihpRwGKjldKHWFZmvoB/AnNV/rXO+HRl3MB5wmO+Dqg3gJZrjGBgDeaV
g9hoQjK6ZwJBAMdg57iKLd8uUb7c4pR8fDdDbeeI5X7WDf2k9emT3BMPJPQ3EiSf
CStn1hRfp31U9CXEnw94rKHhrdMFrYjdzMECQCcWD3f5qTLt4GAMf5XWj199hLq1
UIbGxdQhuccY9Nk7jJRiXczYb/Fg4KkSCvkFX/G8DAFJdc9xFEyfzAQEN+kCQH3a
nMrvZn9gBLffRKOIZPyZctHZp0xGIHTA4X39GMlrIN+Lt8coIKimlgssSlSiAK+q
iuFAQnC5PXlcNyuTHsECQAMNMY6jXikgSUZfVXitAFX3g9+IbjT9eJ92f60QneW8
mxWQoqP3fqCSbTEysb7NojEEwppSZtaNgnBb5R4E+mU=
-----END RSA PRIVATE KEY-----
2 changes: 1 addition & 1 deletion examples/async_recv/src/async_recv_echo_server.app.src
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{application, async_recv_echo_server,
[
{description, "An Erlang async_recv_echo library"},
{vsn, "1"},
{vsn, "1.0"},
{modules, [
async_recv_echo
]},
Expand Down
48 changes: 33 additions & 15 deletions examples/async_recv/src/async_recv_echo_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
%%%-----------------------------------------------------------------------------
-module(async_recv_echo_server).

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

-behaviour(gen_server).

%% start
Expand All @@ -37,7 +39,7 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).

-record(state, {transport, sock}).
-record(state, {conn}).

-define(TCP_OPTIONS, [
binary,
Expand All @@ -52,40 +54,53 @@ start() ->
start([Port]) when is_atom(Port) ->
start(list_to_integer(atom_to_list(Port)));
start(Port) when is_integer(Port) ->
application:start(sasl),
[ok = application:start(App) ||
App <- [sasl, syntax_tools, asn1, crypto, public_key, ssl]],
ok = esockd:start(),
SslOpts = [{certfile, "./crt/demo.crt"},
{keyfile, "./crt/demo.key"}],
SockOpts = [{acceptors, 10},
{max_clients, 100000},
{ssl, SslOpts},
{sockopts, ?TCP_OPTIONS}],
MFArgs = {?MODULE, start_link, []},
esockd:open(echo, Port, SockOpts, MFArgs).

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

init(SockArgs = {Transport, _Sock, _SockFun}) ->
{ok, NewSock} = esockd_connection:accept(SockArgs),
Transport:async_recv(NewSock, 0, infinity),
gen_server:enter_loop(?MODULE, [], #state{transport = Transport, sock = NewSock}).
init(Conn) ->
{ok, Conn1} = Conn:wait(),
Conn1:async_recv(0, infinity),
gen_server:enter_loop(?MODULE, [], #state{conn = Conn1}).

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

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

handle_info({inet_async, Sock, _Ref, {ok, Data}}, State = #state{transport = Transport, sock = Sock}) ->
{ok, PeerName} = Transport:peername(Sock),
handle_info({inet_async, Sock, _Ref, {ok, Data}}, State = #state{conn = ?ESOCK(Sock) = Conn}) ->
{ok, PeerName} = Conn:peername(),
io:format("~s - ~s~n", [esockd_net:format(peername, PeerName), Data]),
Transport:send(Sock, Data),
Transport:async_recv(Sock, 0, infinity),
Conn:async_send(Data),
Conn:async_recv(0, infinity),
{noreply, State};

handle_info({inet_async, _Sock, _Ref, {error, Reason}}, State) ->
{stop, {shutdown, {inet_async_error, Reason}}, State};
handle_info({inet_async, Sock, _Ref, {error, Reason}}, State = #state{conn = ?ESOCK(Sock)}) ->
io:format("shutdown for ~p~n", [Reason]),
shutdown(Reason, State);

handle_info({inet_reply, Sock ,ok}, State = #state{conn = ?ESOCK(Sock)}) ->
{noreply, State};

handle_info(_Info, State) ->
handle_info({inet_reply, Sock, {error, Reason}}, State = #state{conn = ?ESOCK(Sock)}) ->
io:format("shutdown for ~p~n", [Reason]),
shutdown(Reason, State);

handle_info(Info, State) ->
io:format("~p~n", [Info]),
{noreply, State}.

terminate(_Reason, _State) ->
Expand All @@ -94,3 +109,6 @@ terminate(_Reason, _State) ->
code_change(_OldVsn, State, _Extra) ->
{ok, State}.

shutdown(Reason, State) ->
{stop, {shutdown, Reason}, State}.

28 changes: 15 additions & 13 deletions examples/gen_server/src/gen_echo_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
%%%-----------------------------------------------------------------------------
-module(gen_echo_server).

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

-behaviour(gen_server).

%% start
Expand All @@ -38,7 +40,7 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).

-record(state, {transport, sock}).
-record(state, {conn}).

-define(TCP_OPTIONS, [
binary,
Expand All @@ -61,32 +63,32 @@ start(Port) when is_integer(Port) ->
MFArgs = {?MODULE, start_link, []},
esockd:open(echo, Port, SockOpts, MFArgs).

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

init(SockArgs = {Transport, _Sock, _SockFun}) ->
{ok, NewSock} = esockd_connection:accept(SockArgs),
Transport:setopts(NewSock, [{active, once}]),
gen_server:enter_loop(?MODULE, [], #state{transport = Transport, sock = NewSock}).
init(Conn) ->
{ok, Conn1} = esockd_connection:ack(Conn),
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{transport = Transport, sock = Sock}) ->
{ok, PeerName} = Transport:peername(Sock),
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]),
Transport:send(Sock, Data),
Transport:setopts(Sock, [{active, once}]),
Conn:send(Data),
Conn:setopts([{active, once}]),
{noreply, State};

handle_info({tcp_error, Sock, Reason}, State=#state{sock = Sock}) ->
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{sock=Sock}) ->
handle_info({tcp_closed, Sock}, State=#state{conn = ?ESOCK(Sock)}) ->
io:format("tcp_closed~n"),
{stop, normal, State};

Expand Down
Loading

0 comments on commit 9be95f2

Please sign in to comment.