From f379c344c7f30b16e9e0291137dc52a26e51011b Mon Sep 17 00:00:00 2001 From: hanshuaikang <1758504262@qq.com> Date: Sat, 4 Jan 2025 16:07:37 +0800 Subject: [PATCH] feat: supports concurrent pinging of n ip's under one address. --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 1 + README_ZH.md | 1 + src/main.rs | 39 ++++++++++++++++++++++++++------------- src/network.rs | 41 ++++++++++++++++++++++++++--------------- 6 files changed, 56 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d99a19f..7b246d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -494,7 +494,7 @@ dependencies = [ [[package]] name = "nping" -version = "0.2.0" +version = "0.2.1" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 5779aeb..6ab750d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nping" -version = "0.2.0" +version = "0.2.1" edition = "2021" [dependencies] diff --git a/README.md b/README.md index a2ffa0b..9259ee3 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ nping --help - Supports visual latency display - Real-time display of maximum, minimum, average latency, packet loss rate, and other metrics - Support IpV4 and IpV6 +- Supports concurrent pinging of n ip's under one address. ## TODO: - Support dynamic layout display diff --git a/README_ZH.md b/README_ZH.md index fd97f67..74936a3 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -34,6 +34,7 @@ nping --help - 支持可视化延迟展示 - 实时最大最小平均延迟丢包率等指标展示 - 支持 IpV4 和 IpV6 +- 支持一个地址下并发 Ping n 个 ip ## TODO: - 支持动态布局展示 diff --git a/src/main.rs b/src/main.rs index 33ec5cc..79f656c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -// 引入自定义模块 mod network; mod ui; mod terminal; @@ -13,9 +12,9 @@ use crate::network::send_ping; #[derive(Parser, Debug)] #[command( - version = "v0.2.0", + version = "v0.2.1", author = "hanshuaikang", - about = "🏎 Nping with concurrent,chart,multiple addresses,real-time data update" + about = "🏎 Nping mean NB Ping, A Ping Tool in Rust with Real-Time Data and Visualizations" )] struct Args { /// Target IP address or hostname to ping @@ -33,6 +32,13 @@ struct Args { #[clap(long = "force_ipv6", default_value_t = false, short = '6', help = "Force using IPv6")] pub force_ipv6: bool, + #[arg( + short = 'm', + long, + default_value_t = 0, + help = "Specify the maximum number of target addresses, Only works on one target address" + )] + multiple: i32, } @@ -55,7 +61,7 @@ async fn main() -> Result<(), Box> { let targets: Vec = args.target.into_iter().collect::>().into_iter().collect(); - let res = run_app(targets, args.count, args.interval, running.clone(), args.force_ipv6).await; + let res = run_app(targets, args.count, args.interval, running.clone(), args.force_ipv6, args.multiple).await; // if error print error message and exit if let Err(err) = res { @@ -71,6 +77,7 @@ async fn run_app( interval: i32, running: Arc>, force_ipv6: bool, + multiple: i32, ) -> Result<(), Box> { // init terminal @@ -80,10 +87,23 @@ async fn run_app( let terminal = ui::init_terminal().unwrap(); let terminal_guard = Arc::new(Mutex::new(terminal::TerminalGuard::new(terminal))); + let mut addrs = Vec::new(); + // if multiple is set, get multiple IP addresses for each target + if targets.len() == 1 && multiple > 0 { + // 使用get_host_ipaddrs获取多个IP + addrs = network::get_multiple_host_ipaddr(&targets[0], force_ipv6, multiple as usize)?; + } else { + // get IP address for each target + for target in &targets { + let ip = network::get_host_ipaddr(target, force_ipv6)?; + addrs.push(ip); + } + } + // Define statistics variables - let ip_data = Arc::new(Mutex::new(targets.iter().map(|target| IpData { + let ip_data = Arc::new(Mutex::new(addrs.iter().enumerate().map(|(i, _)| IpData { ip: String::new(), - addr: target.to_string(), + addr: if targets.len() == 1 { targets[0].clone() } else { targets[i].clone() }, rtts: VecDeque::new(), last_attr: 0.0, min_rtt: 0.0, @@ -95,13 +115,6 @@ async fn run_app( let errs = Arc::new(Mutex::new(Vec::new())); - // Resolve target addresses - let mut addrs = Vec::new(); - for target in targets { - let ip = network::get_host_ipaddr(&target, force_ipv6)?; - addrs.push(ip); - } - let interval = if interval == 0 { 500 } else { interval * 1000 }; let mut tasks = Vec::new(); for (i, addr) in addrs.iter().enumerate() { diff --git a/src/network.rs b/src/network.rs index e69b664..f30303e 100644 --- a/src/network.rs +++ b/src/network.rs @@ -7,7 +7,8 @@ use pinger::{ping, PingOptions, PingResult}; use crate::ip_data::IpData; // get host ip address default to ipv4 -pub(crate) fn get_host_ipaddr(host: &str, force_ipv6: bool) -> Result> { +pub(crate) fn resolve_host_ips(host: &str, force_ipv6: bool) -> Result, Box> { + // 获取所有IP地址 let ipaddr: Vec<_> = (host, 80) .to_socket_addrs() .with_context(|| format!("failed to resolve host: {}", host))? @@ -18,21 +19,31 @@ pub(crate) fn get_host_ipaddr(host: &str, force_ipv6: bool) -> Result Result> { + let ips = resolve_host_ips(host, force_ipv6)?; + Ok(ips[0].to_string()) +} - Ok(ipaddr.to_string()) +pub(crate) fn get_multiple_host_ipaddr(host: &str, force_ipv6: bool, multiple: usize) -> Result, Box> { + let ips = resolve_host_ips(host, force_ipv6)?; + Ok(ips.into_iter() + .take(multiple) + .map(|ip| ip.to_string()) + .collect()) } @@ -93,7 +104,7 @@ impl PingTask { PingResult::Pong(duration, _size) => { // calculate rtt let rtt = duration.as_secs_f64() * 1000.0; - let rtt_display: f64 = format!("{:.2}", rtt).parse().unwrap(); + let rtt_display: f64 = format!("{:.2}", rtt).parse().unwrap(); update_stats( self.ip_data.clone(), self.index,