ocaml-event를 이용한 echo server

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 )

1402904692.tgz

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>