Here is a simple UDP server:
-module(kvstore_udpserver).
-author("mylesmcdonnell").
%% API
-export([start/0]).
start() ->
spawn(fun() -> server(2346) end).
server(Port) ->
{ok, Socket} = gen_udp:open(Port, [binary]),
loop(Socket).
loop(Socket) ->
receive
{udp, Socket, Host, Port, Bin} ->
case binary_to_term(Bin) of
{store, Value} ->
io:format("kvstore_udpserver:{store, Value}~n"),
gen_udp:send(Socket,Host,Port,term_to_binary(kvstore:store(Value)));
{retrieve, Key} ->
io:format("kvstore_udpserver:{retrieve, Value}~n"),
gen_udp:send(Socket,Host,Port,term_to_binary(kvstore:retrieve(Key)))
end,
loop(Socket)
end.
How can I restructure this so that
a) It, or at least the relevant part of it, is a gen_server so that I can add to the supervision tree
b) increase concurrency by handling each message in a separate process.
I have reimplemented the sockserv example from Learn You Some Erlang for my TCP server but I'm struggling to determine a similar model for UDP.
For a):
You need to delcare the gen_server behaviour and implement all the callback functions (this is obvious, but it's worth calling out explicitly). If you have rebar installed, you can use the command rebar create template=simplesrv srvid=your_server_name to add the boilerplate functions.
You'd probably want to move the server starting business logic (the gen_udp:open/2 call) to your server's init/1 function. (The init is required by the gen_server behaviour. You can also start your loop/1 function there.
You'd probably want to make sure the udp server is closed by the module's terminate/2 function.
Move the business logic for handling requests that come in from parsing the messages to your loop/1 function into handle_call/3 or handle_cast/2 in your module (see below).
For b):
You have a few options, but basically, whenever you receive a message, you can use gen_server:cast/2 (if you don't care about the response) or gen_server:call/2,3 if you do. The casts or calls will be handled by the handle_cast/2 or handle_call/3 functions in your module.
Casts are inherently non-blocking and the answers to this question have a good design pattern for handling call operations asynchronously in gen_servers. You can crib from that.
Related
If I have a group of gen servers called lock, can I call a function say
hello() ->
io:format("Hello, world!~n").
from the Pid of individual processes of that gen_server instead of generic lock:hello().
I tried Pid=<0.91.0> (so the Pid is return when i start a chld in my supervisor), and Pid:hello(). gives a bad argument is it impossible to do this??
Is it a better idea to send a message instead to call that function??
You can call gen_server:call(Pid, TuplePatternThatMatchesOnCallback)
-behaviour(gen_server).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
...
hello() ->
gen_server:call(Pid, hello).
handle_call(hello, _From, _State) ->
Reply = io:format("Hello, world!~n")
{reply, Reply, State}.
There is no Pid:Function API in Erlang.
In both cases calling gen server will serialize the call, providing you are using gen_server API. But going with function call you can choose synchronous reply.
If the hello is just placed in gen_server module (without gen_server:call) it will be executed in context of calling process, not gen_server one's.
When you call a function in a gen_server module, the function is not executed in the gen_server process. It is executed in the caller process.
If you want the gen_server process to do something, you should use the gen_server:call or the gen_server:cast functions:
For example, the gen_server:call/2 function will take a pid and a message that will be sent along with the call. The gen_server will then run it's handle_call function in the gen_server process.
Normally, you would have functions in the same module that defines the gen_server that will do the gen_server:call so that the caller will not have to care. That creates a clean API for others and hides the gen_server specific stuff.
It may be a little bit tricky to get all the pieces together but it's simple once you have. Check out this chapter of LYSE:
http://learnyousomeerlang.com/clients-and-servers
You can call the function hello from anywhere you want. If you call it 1000 times from 1000 processes, each process will be executing the function in parallel not interfering with each other. You just call it like that lock:hello(). from each one of those processes, so you call a specific function hello that is defined in a specific module lock and which takes zero arguments.
Probably there is something you didn't mention in your question?
I'd like to execute some procedure on a remote node. And I'm not sure which is the best way to do this. I can write a rpc:call to do this. Or send a message by Remote ! {call, some_procedure} to the node to start the procedure and use receive waiting for the response. So which way is better in erlang? Or they actually are for different usage?
It's better to use module rpc, because if you don't: you'll have to manage monitoring of remote node, have to provide unique id of the call, handle timeouts, also you're have to provide wrapper to send-back response with result of function.
But all of these manipulations are generic, and implemented in rpc module.
By the way, there are different variations of remote calls, which implemented in rpc: synchronous and asynchronous calls, cast (send message which doesn't need response), even parallel map function (pmap).
P.S.
Compare - simply using rpc:call vs. implement that from scratch (also, this is simple implementation, which doesn't handle some important cases):
-module(myrpc).
-compile(export_all).
server() ->
receive
{{CallerPid, Ref}, {Module, Func, Args}} ->
Result = apply(Module, Func, Args),
CallerPid ! {Ref, Result}
end.
call(Node, Module, Func, Args) ->
monitor_node(Node, true),
RemotePid = spawn(Node, ?MODULE, server, []),
Ref = make_ref(),
RemotePid ! {{self(), Ref}, {Module, Func, Args}},
receive
{Ref, Result} ->
monitor_node(Node, false),
Result;
{nodedown, Node} ->
error
end.
rpc seems to be comprehensive solution, but it has some disadvantages related to scale. rpc uses single 'rex' server to cross node communication and potentially it may be overwhelmed. If you go with rpc, you should monitor this process.
If the communication is the main functionality and it is the top of io/cpu/memory consumer I would consider writing it yourself. On the other hand we may expect improvements from OTP team (and pre-mature optimization is root of all evil!!!).
I'm currently writing a piece of software in erlang, which is now based on gen_server behaviour. This gen_server should export a function (let's call it update/1) which should connect using ssl to another service online and send to it the value passed as argument to the function.
Currently update/1 is like this:
update(Value) ->
gen_server:call(?SERVER, {update, Value}).
So once it is called, there is a call to ?SERVER which is handled as:
handle_call({update, Value}, _From, State) ->
{ok, Socket} = ssl:connect("remoteserver.com", 5555, [], 3000).
Reply = ssl:send(Socket, Value).
{ok, Reply, State}.
Once the packet is sent to the remote server, the peer should severe the connection.
Now, this works fine with my tests in shell, but what happens if we have to call 1000 times mymod:update(Value) and ssl:connect/4 is not working well (i.e. is reaching its timeout)?
At this point, my gen_server will have a very large amount of values and they can be processed only one by one, leading to the point that the 1000th update will be done only 1000*3000 milliseconds after its value was updated using update/1.
Using a cast instead of a call would leave to the same problem. How can I solve this problem? Should I use a normal function and not a gen_server call?
From personal experience I can say that 1000 messages per gen_server process wont be a problem unless you are queuing big messages.
If from your testing it seems that your gen_server is not able to handle this much load, then you must create multiple instances of your gen_server preferably under a supervisor process at the boot time (or run-time) of your application.
Besides that, I really don't understand the requirement of making a new connection for each update!! you should consider some optimization like cached connections/ pre-connections to the server..no?
I am a beginner with erlang, and i write a basic gen server program as follows, I want to know, how to test the server so i can know it works well.
-module(gen_server_test).
-behaviour(gen_server).
-export([start_link/0]).
-export([alloc/0, free/1]).
-export([init/1, handle_call/3, handle_cast/2]).
start_link() ->
gen_server:start_link({local, gen_server_test}, ch3, [], []).
alloc() ->
gen_server:call(gen_server_test, alloc).
free(Ch) ->
gen_server:cast(gen_server_test, {free, Ch}).
init(_Args) ->
{ok, channels()}.
handle_call(alloc, _From, Chs) ->
{Ch, Chs2} = alloc(Chs),
{reply, Ch, Chs2}.
handle_cast({free, Ch}, Chs) ->
io:format(Ch),
io:format(Chs),
Chs2 = free(),
{noreply, Chs2}.
free() ->
io:format("free").
channels() ->
io:format("channels").
alloc(chs) ->
io:format("alloc chs").
BTW: The program can be compiled, and it is not a good program, I just want to print something to make sure it works :)
The beauty of a gen_server implementing module is that it is just a callback module. One need not even have to spawn the underlying gen_server process to test it.
All you need to do is have your test framework (usually eunit) to invoke all the handle_call/cast/info functions by injecting it with different inputs (different gen_server states, different input messages) etc. and ensure it returns the correct response tuple (for eg. {reply, ok, NewState} or {noreply, NewState} etc.)
Ofcourse, this wouldnt work perfectly if your callback functions arn't pure functions. For eg., in your handle_call function, if you are sending a message to another process for eg., or if you are modifying an ets table. In which case, you have to ensure that all the required processes and tables are pre-created before running the test.
You could try one of the following:
Use the erlang shell and invoke the commands manually. Make sure the source or .beam file is in the Erlang path (parameter -pz, like this: erl -pz <path here>)
Write an EUnit test case
PS: I think you have an error in your code, because you seem to start the module ch3 as the server, not the gen_server_test module.
Using the default Erlang installation what is the minimum code needed to produce a "Hello world" producing web server?
Taking "produce" literally, here is a pretty small one. It doesn't even read the request (but does fork on every request, so it's not as minimal possible).
-module(hello).
-export([start/1]).
start(Port) ->
spawn(fun () -> {ok, Sock} = gen_tcp:listen(Port, [{active, false}]),
loop(Sock) end).
loop(Sock) ->
{ok, Conn} = gen_tcp:accept(Sock),
Handler = spawn(fun () -> handle(Conn) end),
gen_tcp:controlling_process(Conn, Handler),
loop(Sock).
handle(Conn) ->
gen_tcp:send(Conn, response("Hello World")),
gen_tcp:close(Conn).
response(Str) ->
B = iolist_to_binary(Str),
iolist_to_binary(
io_lib:fwrite(
"HTTP/1.0 200 OK\nContent-Type: text/html\nContent-Length: ~p\n\n~s",
[size(B), B])).
For a web server using only the built in libraries check out inets http_server.
When in need of some more power but still with simplicity you should check out the mochiweb library. You can google for loads of example code.
Do you actually want to write a web server in Erlang, or do you want an Erlang web server so that you can create dynamic web content using Erlang?
If the latter, try YAWS. If the former, have a look at the YAWS source code for inspiration
Another way, similar to the gen_tcp example above but with less code and already offered as a suggestion, is using the inets library.
%%%
%%% A simple "Hello, world" server in the Erlang.
%%%
-module(hello_erlang).
-export([
main/1,
run_server/0,
start/0
]).
main(_) ->
start(),
receive
stop -> ok
end.
run_server() ->
ok = inets:start(),
{ok, _} = inets:start(httpd, [
{port, 0},
{server_name, "hello_erlang"},
{server_root, "/tmp"},
{document_root, "/tmp"},
{bind_address, "localhost"}
]).
start() -> run_server().
Keep in mind, this exposes your /tmp directory.
To run, simply:
$ escript ./hello_erlang.erl
For a very easy to use webserver for building restful apps or such check out the gen_webserver behaviour: http://github.com/martinjlogan/gen_web_server.
Just one fix for Felix's answer and it addresses the issues Martin is seeing. Before closing a socket, all data being sent from the client should be received (using for example do_recv from gen_tcp description).
Otherwise there's a race condition for the browser/proxy sending the HTTP request being quick enough to send the http request before the socket is closed.