1

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)       
4

2 に答える 2

6

大げさな推測として、タイムアウトの場合はソケットを強制的に閉じる必要があると思います。そのため、カルプリントは次のようになります。

pick [connect_close ; Lwt_unix.timeout timeout]
于 2012-11-09T08:19:15.203 に答える
1

これがトーマスによる修正されたコードです。

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)
于 2012-11-09T23:17:32.497 に答える