2009-01-18

Erlang/OTP UDP Server

얼랭으로 만든, 가장 단순한 UDP Echo 서버와 클라이언트는 이렇게 생겨먹었다. (워드프레스에서 들여쓰기가 자꾸 날아가는 버그가 있으므로, 귀찮아서 고치지는 않겠다.)


-module(udp_server).
-compile(export_all).

init(ServerPort) ->
{ok, Sock} = gen_udp:open(ServerPort,[binary,inet]),
loop().

loop() ->
io:format("server_loop~n"),
receive
{udp, Sock, ClientIP, ClientPort, Packet } ->
io:format("~p:~p ==> ~p~n",[ClientIP,ClientPort,Packet]),
ok = gen_udp:send(Sock,ClientIP,ClientPort,Packet),
loop()
end.


-module(udp_client).
-compile(export_all).

init(ServerPort) ->
{ok, Sock} = gen_udp:open(0),
gen_udp:send(Sock,"localhost",ServerPort,"Hello World!"),
loop().

loop() ->
io:format("waiting response...~n"),
receive
{udp, Peer, PeerIP, PeerPort, Packet } ->
io:format("~p:~p ==> ~p~n",[PeerIP,PeerPort,Packet])
after 1000 ->
io:format("timeout..~n")
end.

여기에서 바로 OTP로 만들겠다고 뛰어들었다가 삽질을 한 후,  Building_a_Non-blocking_TCP_server_using_OTP_principles구글에서 검색한 gen_udp 예제을 참고해서 겨우 성공한 게 다음의 코드이다.



-module(udp_otp_server).
-compile(export_all).

% stand-alone server version
start() ->
gen_server:start({local, ?MODULE}, ?MODULE, [], []).

% supervision tree version
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

init([]) ->
process_flag(trap_exit,true),
{ok, Sock} = gen_udp:open(1111,[binary,inet]),
io:format("udp server started...~n"),
{ok,0}.

handle_call(Request, From, State) ->
io:format("~p~n",[Request]),
{noreply,State}.

handle_cast(_Msg,State) ->
io:format("handle_cast(~p)~n",_Msg),
{noreply, State}.

%% udp message should be handled here
handle_info({udp,Sock, ClientIP, ClientPort, Packet}, State) ->
io:format("~p:~p ==> ~p~n",[ClientIP,ClientPort,Packet]),
ok = gen_udp:send(Sock,ClientIP,ClientPort,Packet),
{noreply, State}
;

handle_info(_Info,State) ->
io:format("handle_info~n"),
{noreply, State}.

terminate(_Reason,N) ->
io:format("stopping...~n"),
ok.
code_change(_OldVsn,N, _Extra) -> {ok,N}.

핵심 요지는, UDP 메시지는 handle_call 이나 cast 가 아니라, handle_info에서 처리해야 한다는 점이다. 요즘 업.무.가. 바.빠.서. 얼랭을 3주 정도 못봤는데 또 서서히 기억이 소멸하기 시작했다. OTP에서는 함수의 리턴값 규칙을 정말 잘 맞춰야 하는 관계로, 다음 번부터는 gen_server 템플릿 하나 정도는 갖고 시작해야겠다.


comments powered by Disqus