Hi Raphael,
The problem with not being able to close connection 2 while connection 1 is still being serviced is likely due to this code using system call functions from module Unix, rather than Lwt_unix (or other Lwt modules). Lwt doesn’t turn Unix module system calls, such as Unix.recv, into non-blocking ones – they can still block your whole program, even if you use Lwt elsewhere in it. Only the Lwt_unix system call functions are non-blocking. To get good results, you have to switch to using those when you switch to Lwt.
There are several other problems of a similar flavor. For example, Lwt.return (Unix.accept sock) doesn’t create a thread that runs Unix.accept in the background. What that actually does is: it blocks the whole process until Unix.accept completes. Then, it wraps the result of Unix.accept in a “already-finished” Lwt thread (admittedly, the existing Lwt docs are a bit vague on this). There is then no use in “binding” on that thread: it just takes out that result, and is equivalent to simply doing "let fd, caller = Unix.accept sock in”. The Lwt way would be
open Lwt.Infix
Lwt_unix.accept sock' >>= fun (fd, caller) ->
…
or
let%lwt fd, caller = Lwt_unix.accept sock’ in (* if building with lwt.ppx *)
...
where sock’ is created by “Lwt_unix.of_unix_file_descr sock”, or better, directly by calling Lwt_unix.socket in the first place.
In general, Lwt threads don’t correspond to system threads, so you can’t just wrap existing code in Lwt.return and Lwt.bind, and expect it to become concurrent. Lwt threads correspond to promises (a.k.a. green threads, pick your term), so you have to use "promise-friendly" versions of everything.
If you’d like to discuss this, or your code, in some detail, I recommend #ocaml on freenode. I lurk there, as do many other Lwt users, and we can quickly go back and forth :)
Best,
Anton
Thanks for your answer!
I get the same result with the following code. Note that I can open 2 connections and that the closing of the connection works as expected with a 'close connection' pattern (with one line only with a dot followed by an empty line). It is just that I cannot close the second connection while the first stays open, the 'close connection' pattern is not triggering the close.
let rec accept_connection sock:Unix.file_descr =
let socket_thread = Lwt.return ( Unix.accept sock ) in
let _ = Lwt.bind socket_thread
( fun (fd, caller) ->
ignore(Lwt_io.printf "accepted\n%!");
(*let _ = set_nonblock fd in*)
Lwt.return (readall fd) >>= fun a ->
ignore(Lwt_io.printf "%s\n%!" a);
ignore(Lwt.async (fun () -> Lwt.return (close fd) ) );
Lwt.return 0;
); in
accept_connection sock
let server port =
let inet_addr = inet_addr_any in
let sockaddr = ADDR_INET (inet_addr, port) in
let domain = domain_of_sockaddr sockaddr in
let sock:Unix.file_descr = socket domain SOCK_STREAM 0 in
Unix.bind sock sockaddr;
listen sock 10;
Lwt_main.run ( Lwt.return (accept_connection sock) )