C# 多线程 ping

Posted

技术标签:

【中文标题】C# 多线程 ping【英文标题】:C# multi-thread ping 【发布时间】:2011-03-07 11:04:06 【问题描述】:

我正在开发一个网络监控应用程序,它会 ping 一个(未知)数量的主机。到目前为止,我有下面的代码。我已经用函数zping 创建了一个类PingHost,并且我在计时器的帮助下每2 秒调用一次,以让2 个ping 完成,即使其中一个得到TimedOut。但我认为更好的解决方案是为每个 ping 生成一个新线程,以便每个主机的 ping 都是独立的。

谁能给我一个提示如何做到这一点?

namespace pinguin

    public partial class Form1 : Form
    
        public Form1()
        

            InitializeComponent();


        

        private void timer1_Tick(object sender, EventArgs e)
        

            PingHost caca = new PingHost();
            PingHost caca1 = new PingHost();
            this.label1.Text = caca.zping("89.115.14.160");
            this.label2.Text = caca1.zping("89.115.14.129");



        

    

    public class PingHost
    


        public string zping(string dest)
        
            Application.DoEvents();
            Ping sender = new Ping();
            PingOptions options = new PingOptions();
            options.DontFragment = true;

            string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            int timeout = 50;
            int failed = 0;
            int pingAmount = 5;
            string stat = "";
            PingReply reply = sender.Send(dest, timeout, buffer, options);
            if (reply.Status == IPStatus.Success)
            
                stat = "ok";
            
            else
            
                stat = "not ok!";
            



            return stat;
        
    

【问题讨论】:

这似乎适合Code Review。 你可能想看看这个以前的问题和答案 - ***.com/questions/4886691/… 为什么不从这里开始:msdn.microsoft.com/en-us/library/aa645740%28v=vs.71%29.aspx 【参考方案1】:

如果您使用 .NET 4,则可以使用 Parallel.Invoke

【讨论】:

【参考方案2】:

您可以处理Ping.PingCompleted 事件:

ping.PingCompleted += new PingCompletedEventHandler(ping_PingCompleted);

然后使用:

ping.SendAsync()

旁注:为您的类和例程选择更合适的名称。 PingHost 更适合作为例程名称

【讨论】:

【参考方案3】:

一旦我写了这样一个解决方案(它不断 ping 大约 300 台机器):

public class ManyAdressPing 
    private readonly bool bAutoStarted;
    private readonly CancellationTokenSource cancel = new CancellationTokenSource();
    public ConcurrentDictionary<IPAddress, OneAddressPing> pingi = new ConcurrentDictionary<IPAddress, OneAddressPing>();
    public ManyAdressPing(bool AutoStarted = true) 
        bAutoStarted = AutoStarted;
    
    public int CountPings => pingi.Count;
    public void AddPingAddress(IPAddress addr, int msTimeOut = 3000, int BetweenPing = 3000) 
        var oap = new OneAddressPing(addr, cancel.Token, msTimeOut, BetweenPing);
        if (bAutoStarted) oap.Start();
        pingi.TryAdd(oap.ipAddress, oap);
    
    public void RemovePingAddress(IPAddress addr) 
        if (pingi.TryRemove(addr, out var p)) p.Stop();
    
    public void Stop() 
        cancel.Cancel();
        foreach (var pair in pingi) pair.Value.Stop();
    
    public PingReply GetReply(IPAddress addr) 
        if (pingi.ContainsKey(addr)) return pingi[addr].GetReply();
        return null;
    
    public Tuple<long, long> GetSuccessOperation(IPAddress addr) 
        if (pingi.ContainsKey(addr)) return pingi[addr].GetSuccessOperation();
        return null;
    
    public PingReply[] GetReply() 
        PingReply[] ret = pingi.Values.Select(x=>x.GetReply()).ToArray();
        return ret;
    
    public PingInfo GetPingInfo(IPAddress addr) 
        if (pingi.ContainsKey(addr)) 
            var ret = new PingInfo();
            var p = pingi[addr];
            ret.reply = p.GetReply();
            ret.SuccessPing = p._SuccessReply;
            ret.FailPing = p._FailReply;
            ret.LastSuccessPing = p.LastSuccessfullPing;
            return ret;
        

        return null;
    
    public bool IsPinged(IPAddress addr) 
        if (pingi.ContainsKey(addr)) return true;
        return false;
    
    public IPAddress[] GetAddressesPing() 
        return pingi.Keys.ToArray();
    

public class PingInfo 
    public PingReply reply;
    public long SuccessPing = 0;
    public long FailPing = 0;
    public DateTime LastSuccessPing;
    public override string ToString() 
        return $"Sping: SuccessPing last=LastSuccessPing, Fping:FailPing, reply:reply";
    

public class OneAddressPing 
    public static byte[] bu = 
        0
    ;
    public long _FailReply;
    public long _SuccessReply;
    private bool bStop = false;
    private readonly CancellationToken cancellationToken;
    public DateTime LastSuccessfullPing = DateTime.MinValue;
    public int mSecBetweenPing = 3000;
    public Ping ping;
    public PingOptions popt;
    private Task pTask;
    // Here is a self-written LIFO stack
    public LightQueue<PingReply> replys = new LightQueue<PingReply>(10);
    private readonly AutoResetEvent reset = new AutoResetEvent(false);
    private Logger log = null;
    private Task pinging = null;
    public OneAddressPing(IPAddress addr, CancellationToken ct, int timeOut = 3000, int BetweenPing = 3000, Logger _log =null) 
        ipAddress = addr;
        popt = new PingOptions();
        popt.DontFragment = false;
        cancellationToken = ct;
        mSecTimeOut = timeOut;
        mSecBetweenPing = BetweenPing;
        log = _log;
    
    public int mSecTimeOut  get; set;  = 3000;
    public IPAddress ipAddress  get; set; 
    public int CountPings => replys.Length;
    private void SetReply(PingReply rep) 
        if (rep == null) return;
        replys.Put(rep);
        if (rep.Status == IPStatus.Success) 
            Interlocked.Increment(ref _SuccessReply);
            LastSuccessfullPing = DateTime.Now;
         else 
            Interlocked.Increment(ref _FailReply);
        
    
    public async Task Start() 
        if (pTask == null || pTask.Status != TaskStatus.Running) 
            ping = new Ping();
            Task.Factory.StartNew(PingCircle, TaskCreationOptions.RunContinuationsAsynchronously | TaskCreationOptions.LongRunning);                 pTask = Task.Run(PingCircle, cancellationToken);
        
    
    public void Stop() 
        if (pTask.Status == TaskStatus.Running) 
            bStop = true;
            try 
                pTask.Wait(mSecTimeOut, cancellationToken);
             catch (Exception ex) 
                log.ErrorSource($"Error ping stop: ex.Message");
             
        
    
    private async Task PingCircle() 
        while (cancellationToken.IsCancellationRequested == false && !bStop) 
            try 
                try 
                    PingReply rep = await ping.SendPingAsync(ipAddress, mSecTimeOut, bu,popt);
                    if (rep != null) SetReply(rep);
                 catch (PingException p) 
                    // ignore ping error
                    Debug.WriteLine($"error: p");
                 catch (Exception ee) 
                    log?.ErrorSource(ee);
                    Debug.WriteLine($"error: ee");
                
                await Task.Delay(mSecBetweenPing, cancellationToken);
             catch (Exception ee) 
                log?.ErrorSource(ee);
            
        
    
    public PingReply GetReply() 
        if (replys.IsEmpty) return null;
        return replys.PeekLast(0);
    
    public Tuple<long, long> GetSuccessOperation() 
        return new Tuple<long, long>(_SuccessReply, _FailReply);
    
    public bool LongPingSuccess() 
        int ret = 0;
        for (int i = 0; i < 5; i++) 
            var r = replys.PeekLast(i);
            if (r.Status == IPStatus.Success) ret++;
        

        if (ret > 2) return true;
        return false;
    

【讨论】:

以上是关于C# 多线程 ping的主要内容,如果未能解决你的问题,请参考以下文章

python 多线程 ping

delphi多线程参数传递问题

Python多线程批量Ping主机IP的脚本

python3实现多线程ping一个网段

python3实现多线程ping一个网段

C#多线程之旅