我想创建一个多线程 ping 应用程序,我可以在其中单击开始,创建n
线程以同时 ping 多个主机,从 GUI 中的线程获取结果并在用户单击取消按钮时取消所有线程。
我已经看到(很多)多线程方法可以做到这一点,但我想要一个代码示例。
有人知道我在哪里可以找到吗?
我想创建一个多线程 ping 应用程序,我可以在其中单击开始,创建n
线程以同时 ping 多个主机,从 GUI 中的线程获取结果并在用户单击取消按钮时取消所有线程。
我已经看到(很多)多线程方法可以做到这一点,但我想要一个代码示例。
有人知道我在哪里可以找到吗?
此示例仅使用 2 个线程,而不是创建多个线程。一个用于发送 ICMP 数据包,一个用于接收回复。您可以在几秒钟内 ping 数千台机器。
//from 1.2.3.1 to 1.2.3.254
var hosts = StackOverflow.Pinger.PingAll("1.2.3.1-254");
//from 1.2.3.1 to 1.2.3.254 and from 1.2.5.1 to 1.2.5.254
var hosts = StackOverflow.Pinger.PingAll("1.2.3,5.1-254");
也可以使用async/await
不阻塞 UI 线程
var hosts = await StackOverflow.Pinger.PingAllAsync(.......);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace StackOverflow
{
public static class Pinger
{
static byte ICMP_ECHO = 8;
static byte ICMP_ECHOREPLY = 0;
static int OFFSET_ID = 4;
static int OFFSET_CHECKSUM = 2;
static int IP_HEADER_LEN = 20;
static int ICMP_HEADER_LEN = 8;
/**************************************************************
* Example Usages:
*
* PingAll("1.2.3.4") => 1.2.3.4
* PingAll("1.2.3.1-255") => 1.2.3.X
* PingAll("1.2.3,7.1-255") => 1.2.3.X and 1.2.7.X
* PingAll("1.2.3-5.1-255") => 1.2.3.X and 1.2.4.X and 1.2.5.X
**************************************************************/
public static IEnumerable<Host> PingAll(string subNets, int timeOut = 1500)
{
ushort PACKET_ID = (ushort)new Random().Next(0, ushort.MaxValue);
//Init
Socket rawSock = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
rawSock.Bind(new IPEndPoint(IPAddress.Any, 0));
rawSock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, 255);
rawSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, Int32.MaxValue);
rawSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, Int32.MaxValue);
rawSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, false);
HashSet<Host> aliveIPs = new HashSet<Host>();
//** Receiver **
Task receiver = Task.Factory.StartNew(() =>
{
byte[] bytesRecv = new byte[0x10000];
EndPoint remoteAddr = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
try
{
rawSock.ReceiveFrom(bytesRecv, ref remoteAddr);
}
catch { return; };
ushort replyId = BitConverter.ToUInt16(bytesRecv, IP_HEADER_LEN + OFFSET_ID);
if (bytesRecv[IP_HEADER_LEN] == ICMP_ECHOREPLY && replyId == PACKET_ID)
{
long ticksInPong = BitConverter.ToInt64(bytesRecv, IP_HEADER_LEN + ICMP_HEADER_LEN);
int duration = (int)((DateTime.Now.Ticks - ticksInPong) / TimeSpan.TicksPerMillisecond);
var host = new Host(((IPEndPoint)remoteAddr).Address.ToString(), duration);
//Console.WriteLine(host.IP + "\t:\t" + host.Duration);
lock (aliveIPs)
{
aliveIPs.Add(host);
}
}
}
}, TaskCreationOptions.LongRunning);
Task.Yield(); //Give a chance to listener task to start.
//** Sender **
for (int j = 0; j < 2; j++)//Send Ping packets twice
{
foreach (var ip in GetIPAddresses(subNets))
{
byte[] packet = CreatePacket(PACKET_ID, BitConverter.GetBytes(DateTime.Now.Ticks));
IPEndPoint dest = new IPEndPoint(IPAddress.Parse(ip), 0);
try
{
rawSock.SendTo(packet, dest);
}
catch (Exception ex)
{
//Console.WriteLine(ex.Message + "\n==>" + ip);
}
}
Task.Delay(timeOut / 3).Wait();
}
Task.WaitAny(receiver, Task.Delay(timeOut));
rawSock.Close();
return aliveIPs;
}
public static Task<IEnumerable<Host>> PingAllAsync(string subNets, int TimeOut = 1500)
{
return Task.Run(() => PingAll(subNets, TimeOut));
}
static byte[] CreatePacket(ushort id, byte[] data)
{
byte[] packet = new byte[ICMP_HEADER_LEN + data.Length];
packet[0] = ICMP_ECHO;
Array.Copy(BitConverter.GetBytes(id), 0, packet, OFFSET_ID, 2); //copy id
Array.Copy(data, 0, packet, ICMP_HEADER_LEN, data.Length); //copy data
Array.Copy(BitConverter.GetBytes(GetChecksum(packet)), 0, packet, OFFSET_CHECKSUM, 2); //copy checksum
return packet;
}
static ushort GetChecksum(byte[] bytes)
{
ulong sum = 0;
int i;
for (i = 0; i < bytes.Length - 1; i += 2)
{
sum += BitConverter.ToUInt16(bytes, i);
}
if (i != bytes.Length)
sum += bytes[i];
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
return (ushort)(~sum);
}
static IEnumerable<string> GetIPAddresses(string ip)
{
string[] parts = ip.Split('.');
if (parts.Length != 4) throw new FormatException("Invalid format");
return
from p1 in GetRange(parts[0])
from p2 in GetRange(parts[1])
from p3 in GetRange(parts[2])
from p4 in GetRange(parts[3])
select String.Format("{0}.{1}.{2}.{3}", p1, p2, p3, p4);
}
static IEnumerable<int> GetRange(string s)
{
foreach (var part in s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
var range = part.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
if (range.Length > 2) throw new FormatException(String.Format("Invalid Format \"{0}\"", range));
if (range.Length == 1) yield return int.Parse(range[0]);
else
{
for (int i = int.Parse(range[0]); i <= int.Parse(range[1]); i++)
{
yield return i;
}
}
}
}
public class Host
{
public string IP { get; private set; }
public int Duration { get; private set; }
public Host(string IP, int duration)
{
this.IP = IP;
this.Duration = duration;
}
public override bool Equals(object obj)
{
return IP.Equals((obj as Host).IP);
}
public override int GetHashCode()
{
return IP.GetHashCode();
}
public override string ToString()
{
return IP;
}
}
}
}