ping.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. use crossbeam_channel::{bounded, select, Receiver};
  2. use pnet::packet::{
  3. icmp::{
  4. echo_reply::{EchoReplyPacket, IcmpCodes},
  5. echo_request::MutableEchoRequestPacket,
  6. IcmpTypes,
  7. },
  8. util, Packet,
  9. };
  10. use signal_hook::consts::{SIGINT, SIGTERM};
  11. use socket2::{Domain, Protocol, Socket, Type};
  12. use std::{
  13. io,
  14. net::{self, Ipv4Addr, SocketAddr},
  15. sync::{
  16. atomic::{AtomicU64, Ordering},
  17. Arc,
  18. },
  19. thread::{self},
  20. time::{Duration, Instant},
  21. };
  22. use crate::{config::Config, error::PingError};
  23. #[derive(Clone)]
  24. pub struct Ping {
  25. config: Config,
  26. socket: Arc<Socket>,
  27. dest: SocketAddr,
  28. }
  29. impl Ping {
  30. ///# ping创建函数
  31. /// 使用config进行ping的配置
  32. pub fn new(config: Config) -> std::io::Result<Self> {
  33. let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::ICMPV4))?;
  34. let src = SocketAddr::new(net::IpAddr::V4(Ipv4Addr::UNSPECIFIED), 12549);
  35. let dest = SocketAddr::new(config.address.ip, 12549);
  36. socket.bind(&src.into())?;
  37. // socket.set_ttl(64)?;
  38. // socket.set_read_timeout(Some(Duration::from_secs(config.timeout)))?;
  39. // socket.set_write_timeout(Some(Duration::from_secs(config.timeout)))?;
  40. Ok(Self {
  41. config,
  42. dest,
  43. socket: Arc::new(socket),
  44. })
  45. }
  46. ///# ping主要执行逻辑
  47. /// 创建icmpPacket发送给socket
  48. pub fn ping(&self, seq_offset: u16) -> anyhow::Result<()> {
  49. //创建 icmp request packet
  50. let mut buf = vec![0; self.config.packet_size];
  51. let mut icmp = MutableEchoRequestPacket::new(&mut buf[..]).expect("InvalidBuffferSize");
  52. icmp.set_icmp_type(IcmpTypes::EchoRequest);
  53. icmp.set_icmp_code(IcmpCodes::NoCode);
  54. icmp.set_identifier(self.config.id);
  55. icmp.set_sequence_number(self.config.sequence + seq_offset);
  56. icmp.set_checksum(util::checksum(icmp.packet(), 1));
  57. let start = Instant::now();
  58. //发送 request
  59. self.socket.send_to(icmp.packet(), &self.dest.into())?;
  60. //处理 recv
  61. let mut mem_buf =
  62. unsafe { &mut *(buf.as_mut_slice() as *mut [u8] as *mut [std::mem::MaybeUninit<u8>]) };
  63. let (size, _) = self.socket.recv_from(&mut mem_buf)?;
  64. let duration = start.elapsed().as_micros() as f64 / 1000.0;
  65. let reply = EchoReplyPacket::new(&buf).ok_or(PingError::InvalidPacket)?;
  66. println!(
  67. "{} bytes from {}: icmp_seq={} ttl={} time={:.2}ms",
  68. size,
  69. self.config.address.ip,
  70. reply.get_sequence_number(),
  71. self.config.ttl,
  72. duration
  73. );
  74. Ok(())
  75. }
  76. ///# ping指令多线程运行
  77. /// 创建多个线程负责不同的ping函数的执行
  78. pub fn run(&self) -> io::Result<()> {
  79. println!(
  80. "PING {}({})",
  81. self.config.address.raw, self.config.address.ip
  82. );
  83. let _now = Instant::now();
  84. let send = Arc::new(AtomicU64::new(0));
  85. let _send = send.clone();
  86. let this = Arc::new(self.clone());
  87. let success = Arc::new(AtomicU64::new(0));
  88. let _success = success.clone();
  89. let mut handles = vec![];
  90. for i in 0..this.config.count {
  91. let _this = this.clone();
  92. let handle = thread::spawn(move || {
  93. _this.ping(i).unwrap();
  94. });
  95. _send.fetch_add(1, Ordering::SeqCst);
  96. handles.push(handle);
  97. if i < this.config.count - 1 {
  98. thread::sleep(Duration::from_millis(this.config.interval));
  99. }
  100. }
  101. for handle in handles {
  102. if handle.join().is_ok() {
  103. _success.fetch_add(1, Ordering::SeqCst);
  104. }
  105. }
  106. let total = _now.elapsed().as_micros() as f64 / 1000.0;
  107. let send = send.load(Ordering::SeqCst);
  108. let success = success.load(Ordering::SeqCst);
  109. let loss_rate = if send > 0 {
  110. (send - success) * 100 / send
  111. } else {
  112. 0
  113. };
  114. println!("\n--- {} ping statistics ---", self.config.address.raw);
  115. println!(
  116. "{} packets transmitted, {} received, {}% packet loss, time {}ms",
  117. send, success, loss_rate, total,
  118. );
  119. Ok(())
  120. }
  121. }
  122. //TODO: 等待添加ctrl+c发送信号后添加该特性
  123. // /// # 创建一个进程用于监听用户是否提前退出程序
  124. // fn signal_notify() -> std::io::Result<Receiver<i32>> {
  125. // let (s, r) = bounded(1);
  126. // let mut signals = signal_hook::iterator::Signals::new(&[SIGINT, SIGTERM])?;
  127. // thread::spawn(move || {
  128. // for signal in signals.forever() {
  129. // s.send(signal).unwrap();
  130. // break;
  131. // }
  132. // });
  133. // Ok(r)
  134. // }