exit 0未终止程序



我正在使用OCaml Unix库中提供的高级网络连接函数在OCaml中开发客户机-服务器应用程序,遵循https://caml.inria.fr/pub/docs/oreilly-book/html/book-ora187.html提供的步骤。这些函数是:

val open_connection : sockaddr -> in_channel * out_channel

val shutdown_connection : in_channel -> unit

val establish_server : (in_channel -> out_channel -> unit) -> sockaddr -> unit

我能够成功构建客户端和验证器,但我不能使用exitOCaml函数终止服务器。

我的(最小)服务器代码如下:

let handle_service ic oc =
try while true do
...
if ... then raise Finish_interaction
done ;
with
| Finish_interaction -> raise Sys.Break
| _ -> ...
let main_server serv_fun =
if Array.length Sys.argv < 4 then ...
else try
let port = int_of_string Sys.argv.(1) in
...
let my_address = Unix.inet_addr_loopback in
Unix.establish_server serv_fun (Unix.ADDR_INET(my_address, port)) 
with
| Sys.Break -> exit 0 (* PROGRAM DOES NOT TERMINATE *)
| _ -> ...
let go_server () = 
Unix.handle_unix_error main_server handle_service ;;
go_server ()

我可以成功捕获Sys.Break异常,但exit 0代码捕获该异常后不做任何事情,服务器只是保持运行并等待另一个客户端连接。

OCaml文档对establish_server有如下说明:

函数Unix.establish_server从未正常返回。

我不知道这是否意味着我不能在没有用户交互的情况下终止程序(例如通过Ctrl + C)。

简而言之,我如何终止我的服务器?客户端在shutdown_connection之后终止,但服务器继续等待传入的连接。顺便说一句,我正在使用OCamlbuild编译我的代码。

来自Unix.establish_server的文档:

为每个连接创建一个新进程

我建议打印进程id (Unix.getpid ()),以确保调用exit的进程是您期望的进程(父进程)。

您可以检查的另一件事是程序在执行at_exit回调时没有卡住。例如,下面的程序在调用exit期间进入一个无限循环:

let () =
at_exit (fun () -> while true do () done);
print_endline "all is well!";
exit 0

(可能不是你现在遇到的问题,但可能对未来的访问者有用)

我设法解决了我的问题,而不需要在进程之间发送信号。

我调整了establish_server函数,这样它就不会创建一个回答所有传入连接的循环。通过删除循环,它将只回答一个传入的连接,然后简单地结束其执行。

下面是新的establish_server函数的代码:
let establish_server server_fun sockaddr =
let domain = Unix.domain_of_sockaddr sockaddr in
let sock = Unix.socket domain Unix.SOCK_STREAM 0 
in Unix.bind sock sockaddr ;
Unix.listen sock 3;
(*while true do*)
let (s, caller) = Unix.accept sock 
in match Unix.fork() with
0 -> if Unix.fork() <> 0 then exit 0 ; 
let inchan = Unix.in_channel_of_descr s 
and outchan = Unix.out_channel_of_descr s 
in server_fun inchan outchan ;
close_in inchan ;
close_out outchan ;
exit 0
| id -> Unix.close s; ignore(Unix.waitpid [] id)
(*done ;;*)

去掉这两行注释就得到了它的原始版本。

感谢大家的回答!

最新更新