ocaml-event(libevent ocaml wrapper)를 이용하여 echo server를 OCaml 언어로 작성해 봤습니다. libevent C API에 익숙해서 ocaml 답지 않게 짜진거 같은 느낌도 들지만 워낙 프로그램이 간단하다보니 크게 틀려질 부분은 없어보이는군요. 다른건 문제가 없었는데 Makefile에서 ocamlopt로 native 컴파일할때 C 라이브러리가 링크가 안되서 약간 헤맸고, printf 후에 flush stdout을 하는 부분이 있는데, stdout이 Unix 네임스페이스에 있는 stdout으로 인식이 되어 컴파일이 안되더군요. 그래서 Pervasives.stdout으로 지정하니 컴파일 잘되네요.
아래는 echo_server_event.ml 소스입니다.
[CODE type=ocaml]
(*
* echo server using libevent
*
* Copyright (c) 2007 Chun-Koo Park
* All rights reserved.
*)
open Unix
let rec sock_write sock buf offset = function
| 0 -> ()
| len ->
let nwritten = write sock buf offset len in
sock_write sock buf (offset + nwritten) (len – nwritten)
let echo_callback event fd event_type =
let buf = String.create 64 and nread = ref 1 in
while !nread > 0 do
nread := read fd buf 0 64;
sock_write fd buf 0 !nread;
done;
if !nread > 0 then
Libevent.add event None
else
Printf.printf “connection closed\n”;
flush Pervasives.stdout
let accept_callback event fd event_type =
let asock, addr = accept fd in
let evnew = Libevent.create () in
Libevent.set evnew asock [Libevent.READ] false (echo_callback evnew);
Libevent.add evnew None;
Libevent.add event None
let tcp_server_sock port =
let ssock = socket PF_INET SOCK_STREAM 0
and addr = inet_addr_any in
bind ssock (ADDR_INET (addr, port));
setsockopt ssock SO_REUSEADDR true;
listen ssock 5;
ssock
let _ =
let listenport = 2007 in
let acceptfd = tcp_server_sock listenport in
let acceptev = Libevent.create () in
Libevent.set acceptev acceptfd [Libevent.READ] false (accept_callback acceptev);
Libevent.add acceptev None;
Libevent.dispatch ()
[/HTML][/CODE]
ocaml-event를 이용한 echo 서버와 thread와 fork로 짠 echo 서버의 Makefile입니다. ocaml findlib를 이용했습니다. ocaml findlib에 대해서 얼마전에 올린글을 참고하세요.
[CODE type=makefile]
# Makefile
#
# Copyright (c) 2007 Chun-Koo Park
# All rights reserved.
OCAMLC=ocamlfind ocamlc
#OCAMLC=ocamlfind ocamlopt
EXEC=echo_server_fork echo_server_thread echo_server_event
all: $(EXEC)
echo_server_fork: echo_server_fork.ml
$(OCAMLC) -o $@ -package unix -linkpkg $@.ml
echo_server_thread: echo_server_thread.ml
$(OCAMLC) -o $@ -thread -package “threads unix” -linkpkg $@.ml
echo_server_event: echo_server_event.ml
$(OCAMLC) -o $@ -package “libevent unix” -linkpkg $@.ml -ccopt -L/usr/local/lib -cclib -levent
clean:
rm -f *.cmo *.cmi *.cmx *.o $(EXEC)
# vi:set noet:
[/HTML][/CODE]
thread 사용할때는 -thread 옵션을 주고, ocamlopt로 native 컴파일할 경우를 위해서 -cclib로 libevent C 라이브러리를 지정해주었습니다. -cclib event로 지정하면 라이브러리를 찾을거라 생각했는데 -cclib -levent 형태로 라이브러리 지정을 해야되더군요. ocamlc로 byte compile할때는 -cclib 를 지정하지 않아도 됩니다.
Ocaml로 작성한 세가지 echo server 소스입니다. ( libevent / fork / thread )