2012-12-17 65 views
-4

我想創建一個多線程的ping應用程序,我可以在其中啓動它,創建n個線程同時ping多個主機,從GUI中的線程獲取結果並取消所有線程if用戶點擊取消按鈕。多線程C#GUI ping示例

我已經看到(很多)多線程方式來做到這一點,但我想要一個代碼示例。

有人知道我在哪裏可以找到那個嗎?

在此先感謝

+0

我有後臺工作,但都沒有成功嘗試... – hotips

回答

5

而不是創建多個線程,此示例只使用2個線程。一個用於發送ICMP數據包,另一個用於接收回復。您可以在幾秒鐘內連接數千臺計算機。

//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; 
      } 
     } 
    } 
} 
+0

是否有可能停止線程或開始時有更新?我ping GPRS網絡上的設備。第一個數據包通常會丟失,平均ping大約爲2500毫秒......謝謝! – hotips

+0

@ si2w上面的代碼向每臺機器發送兩個ICMP數據包。它也有一個超時參數。 –