我想写一个 TCP 端口扫描器,用来判断端口打开和关闭的工具。
以 Rust 官网为例,代码如下:
use rayon::prelude::*;
use std::net::TcpStream;
fn main() {
let result = (0..=65535).into_par_iter().map(|i|
match TcpStream::connect(format!("rust-lang.org:{}", i)) {
Ok(_) => (Some(i), None),
Err(_) => (None, Some(i))
}
).collect::<Vec<_>>();
let open = result.par_iter().filter_map(|i| i.0).collect::<Vec<_>>();
let close = result.into_par_iter().filter_map(|i| i.1).collect::<Vec<_>>();
println!("打开的端口号: {:?}", open);
println!("关闭的端口号: {:?}", close);
}
其中,第 5 行的 map
,以及 12 和 13 行的 filter_map
,它们一共循环了 3 次。
我的问题如下:
- 有没有办法只循环一次?
- rayon 在此场景下,速度仍不够快。有没有更快/更适用的并行方式?
- 对于此需求,并发和并行,哪种更合适?
1
共 8 条评论, 1 页
评论区
写评论试试
partition_map
有一个crate,名字好像是:itertools,提供了类似groupby的操作
--
👇
ltoddy: Rust的迭代器没有Java Stream中的类似GroupBy的方法,所以没法合成一个循环。
试了下,timeout还是放在外层比较好,dns查询也需要时间,或者使用tokio的lookup_host。 https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=99447eaf55ab96957908ac804bae048a
👇
zhylmzr: 对rayon不是很了解,不过需要异步io的时候可以用tokio,用tokio写了一版
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=df8035d5969fbca756e138cef066c680
对rayon不是很了解,不过需要异步io的时候可以用tokio,用tokio写了一版
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=df8035d5969fbca756e138cef066c680
这里瓶颈肯定是在 connect。建议用 tokio 之类的非阻塞 connect,就不用开线程了(即不用 rayon)。
Rust的迭代器没有Java Stream中的类似GroupBy的方法,所以没法合成一个循环。
PS: tcp超时的具体秒数是印象里的,不一定准确,总之协议里的默认超时超过了120s
做了两个优化
我觉得主要慢在tcp超时,tcp协议里握手超时是186秒,建议用
connect_timeout
去代替connect