我正在尝试更好地编写一个小型Lwt(和电池)端口扫描仪 了解Lwt然而,每当我尝试扫描时,我都会遇到一个奇怪的异常 scan_ports_range一次有太多端口。我怀疑我的机制 保持最大连接数打开不起作用...
Exception: Unix.Unix_error (Batteries.Unix.EMFILE, "socket","").
Fatal error: exception Sys_error("/home/(censored)/.opam/4.00.1/lib/utop: Too many open files")
(这也崩溃utop btw)
代码如下。要触发错误评估:
scan_ports_range ~host:"127.0.0.1" (1000,2000)
对我的lwt风格的任何批评/建议也是受欢迎的,因为我已经 才开始学习它。
open Lwt
let addr_parts addr =
let (host, port) = String.split addr ":" in (host, int_of_string port)
let addr ~host ~port =
lwt entry = Lwt_unix.gethostbyname host in
if Array.length entry.Unix.h_addr_list = 0 then begin
failwith (Printf.sprintf "no address found for host %S\n" host)
end;
return (Unix.ADDR_INET (entry.Unix.h_addr_list.(0), port))
let test_connection ?(timeout=1.0) addr =
let fd = Lwt_unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
let connect_close =
(Lwt_unix.connect fd addr) >>= (fun () -> Lwt_unix.close fd) in
try_lwt
(pick [connect_close ; Lwt_unix.timeout timeout])
>>= (fun () -> return true)
with _ -> return false
let scan_ports ~host ~ports =
ports |> Lwt_list.map_p (fun port ->
lwt adr = addr ~host ~port in
test_connection adr >>= (fun res -> return (res,port)) )
>>= (fun l -> return ( l |> List.filter_map ( function
| false, _ -> None | true, port -> Some(port) ) ) )
let scan_ports_range ?(max_open=20) ~host (a, b) =
let rec loop acc enum =
match Enum.peek enum with
| None -> acc |> List.concat |> List.rev |> return
| Some _ ->
let ports = enum |> Enum.take max_open |> List.of_enum in
let open_ports = scan_ports ~host ~ports in
open_ports >>= (fun l -> loop (l::acc) enum )
in loop [] (a--b)
答案 0 :(得分:6)
作为一个疯狂的猜测,我认为你需要在超时的情况下强制关闭套接字,因此剔除可能是:
pick [connect_close ; Lwt_unix.timeout timeout]
答案 1 :(得分:1)
根据Thomas的说法,这是更正后的代码。
let test_connection ?(timeout=1.0) addr =
let fd = Lwt_unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
let connect_close =
(Lwt_unix.connect fd addr) >>= (fun () -> Lwt_unix.close fd) in
try_lwt
(pick [connect_close ; Lwt_unix.timeout timeout])
>>= (fun () -> return true)
with _ -> (Lwt_unix.close fd) >>= (fun () -> return false)