gpt4 book ai didi

OCaml:Lwt 和非阻塞套接字

转载 作者:行者123 更新时间:2023-12-01 06:12:47 25 4
gpt4 key购买 nike

我想为一个简单的客户端尝试使用 Lwt_unix 模块,该客户端读取套接字中的数据,直到没有任何数据可读为止。有人告诉我 Lwt 创建非阻塞套接字,但使用我的代码,它仍然是阻塞的:

open Lwt
open Unix

(* ocamlfind ocamlc -o lwt_socket_client -package lwt,lwt.unix,unix -linkpkg -g lwt_socket_client.ml *)
let host = Unix.inet_addr_loopback
let port = 6600

let create_socket () =
let sock = Lwt_unix.socket PF_INET SOCK_STREAM 0 in
Lwt_unix.set_blocking sock false;
sock

let s_read sock maxlen =
let str = Bytes.create maxlen in
let rec _read sock acc =
Lwt.ignore_result(Lwt_io.write_line Lwt_io.stdout "_read");
Lwt_unix.read sock str 0 maxlen >>= fun recvlen ->
Lwt.ignore_result(Lwt_io.write_line Lwt_io.stdout (string_of_int recvlen));
if recvlen = 0 then Lwt.return (acc)
else _read sock (acc ^ (String.sub str 0 recvlen))
in _read sock ""

let socket_read sock =
Lwt.ignore_result(Lwt_unix.connect sock @@ ADDR_INET(host, port));
s_read sock 1024 >>= fun answer ->
Lwt_io.write_line Lwt_io.stdout answer

let () =
let sock = create_socket () in
Lwt_main.run (socket_read sock)

如果我在一个术语中尝试这个例子:

echo "totoche" | netcat -l 127.0.0.1 -p 6600

那么结果是:

./lwt_socket_client
_read
8
_read

在我按下 Ctrl+c 之前阻塞。

我都试过:

Lwt_unix.set_blocking sock false;

Lwt_unix.set_blocking sock true;

当然没有这条线,但它仍然是阻塞的。我做错了什么?

有关更多信息,我之前的问题之一: OCaml non-blocking client socket

最佳答案

从概念上讲,Lwt_unix.read总是阻塞 Lwt 线程,但从不阻塞整个进程——除非进程正在等待那个 Lwt线程,并且没有其他 Lwt 线程要运行。 Lwt_unix.set_blocking 不会影响此行为。它只是更改底层套接字上的设置,因此更改 Lwt 内部使用的策略以避免阻塞进程。

因此,正如@ThomasLeonard 所提到的,执行非阻塞 read 的“惯用 Lwt”方法(从进程的角度来看)只是简单地同时运行额外的 Lwt 线程与 Lwt_unix.read.


关于问题中的具体代码,如果底层套接字是非阻塞的,但没有数据可用——而不是成功读取零字节,这表明套接字已关闭。

Unix.read 将其转换为异常 Unix.Unix_error Unix.EAGAIN(分别为 Unix.Unix_error Unix.EWOULDBLOCK)。 Lwt_unix.read 在这种情况下重试 Unix.read。因此,如果使用 Lwt_unix.read,您不能(当前)直接响应以这种方式失败的非阻塞读取。

如果您确实想要/需要对使用 Lwt_unix 创建的套接字进行这种级别的控制,您可以这样做:

Lwt_unix.set_blocking sock false;

try
Unix.read (Lwt_unix.unix_file_descr sock) str 0 maxlen
with Unix.Unix_error (Unix.EAGAIN | Unix.EWOULDBLOCK) ->
(* Handle no data available. *)

编辑:另外,正如@ThomasLeonard 所提到的,您的代码中对 ignore_result 的一些使用可能应该是 e >>= fun () -> e'。这会强制 Lwt 在运行 e' 之前等待 e 完成。特别是,您应该为 Lwt_unix.connect 执行此操作。

关于OCaml:Lwt 和非阻塞套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39675231/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com