(* routines for reading and writing while only blocking the
* current thread of execution *)
let thread_read_line fd =
let s = " " and r = ref "" in
while (Unix.read fd s 0 1 > 0) && s.[0] <> '\n' do
r := !r ^ s
done; !r
let thread_write_string fd str =
ignore (Unix.write fd str 0 (String.length str))
let thread_write_endline fd str =
thread_write_string fd (str ^ "\n")
(*** actual networking code ***)
let gen_connection_num =
let c = ref 0 in
(fun () -> incr c; !c)
exception Done
(* just for something to do with our clients, unimportant *)
let counter = ref 0
class connection (sd, sa) = object (self)
val socket = sd
val addr = sa
val mutable number = 0
initializer
number <- gen_connection_num ();
method start () =
Thread.create (fun x ->
self#run x;
self#stop x) ()
method stop () =
Unix.close socket
method run () =
try while true do
(* do things here, terminate the thread with 'raise Done'. as a
* demonstration, we count for our clients, keeping track of a
* server-global counter state *)
let line = thread_read_line socket in
counter := !counter + 1;
thread_write_endline socket (string_of_int !counter)
done with
| Done -> () (* thread terminated normally *)
| exn -> print_string (Printexc.to_string exn); print_newline ()
end
class serv_socket p = object (self)
val port = p
val mutable sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0
val queue_limit = 3
initializer
Unix.bind sock (Unix.ADDR_INET(Unix.inet_addr_any, port));
Unix.listen sock queue_limit
method private client_addr = function
Unix.ADDR_INET(host, _) -> Unix.string_of_inet_addr host
| _ -> "Client connecting from non-internet host???"
method run () =
while true do
let (sd, sa) = Unix.accept sock in
let connection = new connection (sd, sa) in
ignore (connection#start ())
done
end
let _ =
let port = 4226 in
Unix.handle_unix_error (fun () ->
let s = new serv_socket port in s#run ()) ()