用ping方式探测网络连通性--一个小程序

原创 2015年07月07日 13:29:37

问题提出,内网数千台设备,想知道他们是否在线。需然网上很多软件可以实现,但是俺还是想通过自己编程解决,最常用的方法是发ICMP包,看看设备回应。技术要点

  • 如何发ICMP包,接收设备ECHO信息;
  • 采用多线程设计;
  • ECHO信息在数据库持久化;

编程环境

  • Microsoft Visual Studio 2013
  •  Microsoft Windows 7
  • Microsoft .NET FrameWork 4.5

 

俺参考Ping函数 Microsoft 例子,建立一个发ping的函数JobForAThread(object state),传入的参数是数据库表的实例化对象,程序如下:

  staticvoid JobForAThread(object state)

        {

            int pingcount = 3;  //定义ping的次数

            C2011 who = ((C2011)state); //获取数据库实例

            AutoResetEvent waiter = newAutoResetEvent(false); //

            ConnectedFeedback feedback = newConnectedFeedback(who); //一个自定义类,存放返回ECHO数据

            WoodenStick waitcallbackinstance = newWoodenStick(waiter, feedback); //一个自定义类,封装两个类,下面介绍

 

            Ping pingSender = newPing();

            pingSender.PingCompleted+= newPingCompletedEventHandler(PingCompletedCallback); //聆听ping响应,定义处理函数PingCompletedCallback

 

            string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; //定义发送ping的缓存区

            byte[] buffer = Encoding.ASCII.GetBytes(data);

            int timeout = 5000;  //ping 超时阙值

            PingOptions options = newPingOptions(64, true); // pingOption属性

 

            for (int i = 0; i < pingcount; i++)

            {

               pingSender.SendAsync(who.IP, timeout, buffer, options,waitcallbackinstance);//ping包,将类waitcallbackinstance传递到ping响应处理函数

                waiter.WaitOne(); //ping响应无这么快回来,线程无事干,阻塞等候

            }

 

           feedback.Average(pingcount); //计算多次ping的结果,取平均值

 

            //将结果实例化到CO_PingRecord 对象,准备持久化到数据库

CO_PingRecord copingrecord = newCO_PingRecord();

            copingrecord.IP_Adress =feedback.NetIPaddress.ToString();

           copingrecord.Connectivity = feedback.Connectivity;

           copingrecord.RoundTripTime = (int)feedback.RoundTripTime;

            copingrecord.TTL =feedback.TimeToLive;

            copingrecord.CreatDate =DateTime.Now;

           copingrecord.ConnectivityRate = feedback.rate;

            copingrecord.C2011_ID =feedback.C2011ID;

           

            //定义一个DataContext作为数据库连接

            DBAppDataContext db = newDBAppDataContext();

 

            //使用事务处理数据库数据写入

            using (TransactionScope ts = newTransactionScope())

            {

                try

                {   // 插入一个对象,该对象保存计算ECHO结果

                   db.CO_PingRecords.InsertOnSubmit(copingrecord);

                   db.SubmitChanges();

                    ts.Complete();

                }

                catch (SqlException e)

                {

                    Console.WriteLine(e.Message);

                }

                catch (Exception e)

                {

                    Console.WriteLine(e.Message);

                }

            }

//输出信息

            Console.WriteLine("IP: {0}/Connectivity: {1}/PingStatusValue:{2}",feedback.NetIPaddress, feedback.Connectivity, feedback.rate);

            Console.WriteLine("IP: {0} Ping example completed.DateTime: {1}", feedback.NetIPaddress, DateTime.Now);

//释放资源,不写 .NET也有垃圾回收机制

            pingSender.Dispose();

            db.Dispose();

        }

 

上述提到一个ping处理响应函数PingCompletedCallback,他是这样的

privatestaticvoid PingCompletedCallback(object sender, PingCompletedEventArgs e)

        {

            // 如果操作取消,显示信息.

            if (e.Cancelled)

            {

                Console.WriteLine("Pingcanceled.");

 

                //唤醒委托线程.

                ((AutoResetEvent)((WoodenStick)e.UserState).AutoResetEventMembers).Set();

            }

 

            // 如果发生错误,显示信息.

            if (e.Error != null)

            {

                Console.WriteLine("Pingfailed:");

                Console.WriteLine(e.Error.ToString());

 

                //唤醒委托线程.

                ((AutoResetEvent)((WoodenStick)e.UserState).AutoResetEventMembers).Set();

            }

 

            ConnectedFeedback feedback = (ConnectedFeedback)((WoodenStick)e.UserState).ConnectedFeedbackMembers;

 

            PingReply reply = e.Reply;

            DisplayReply(reply,feedback);

 

            // 唤醒ping发送线程. 使得waiter.WaitOne()被触发,程序继续运行

            ((AutoResetEvent)((WoodenStick)e.UserState).AutoResetEventMembers).Set();

        }

 

数据处理及显示

publicstaticvoid DisplayReply(PingReply reply, ConnectedFeedback feedback)

        {

            if (reply == null)

                return;

            if (reply.Status == IPStatus.Success)

            {// 计算ECHO返回

               feedback.PingFeedbackCalculate(reply);

            }

        }

Ping的函数已经写好,现在轮到多线程执行它,俺使用线程池

DBAppDataContext db = newDBAppDataContext();          

            IEnumerable<C2011> c2012;

            Console.WriteLine("*********Program PingsStart.************");

 

            int nWorkerThreads;

            int nCompletionPortThreads;

            ThreadPool.SetMaxThreads(64, 128);

            ThreadPool.GetMaxThreads(out nWorkerThreads, out nCompletionPortThreads);

            Console.WriteLine("Max worker threads: {0}, I/Ocompletion" +

                 "threads:{1}",nWorkerThreads, nCompletionPortThreads);

 

            int workerThreads;

            int completionPortThreads;

            int difference;

 

            bool flag = true;

 

            while (flag)

            {

                //立即执行查询,数据库IP是动态变化的,需要每周期取一次;

                c2012 =db.GetTable<C2011>().Where(c => c.IP != "0.0.0.0").ToList();

                //这儿有点奇怪,上述语句可以使c2012刷新数据库增加和删除的记录,但不会刷新更行记录,所以增加这语句

db.Refresh(RefreshMode.OverwriteCurrentValues,c2012);

 

                foreach (var item in c2012)

                {

                    try

                    {

                        //按任意键退出

                        if (Console.KeyAvailable)

                        {

                            flag = false;

                            break;

                        }

                        //主线程不要执行得太快,等一下其他线程。

                        ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);

                        difference =nWorkerThreads - workerThreads;

                        if (difference >= 10)

                        {

                            Thread.Sleep(2000);

                        }

                        else

                        {

                            Thread.Sleep(500);

                        }

                        Console.WriteLine("***Ping  IP : {0} Start.***", item.IP);

                        //调度线程池的线程处理ping

                        ThreadPool.QueueUserWorkItem(newWaitCallback(JobForAThread), item);

                    }

                    catch (ArgumentNullException e)

                    {

                        Console.WriteLine("ArgumentNullExceptioncaught!!!");

                        Console.WriteLine("Source :" +e.Source);

                        Console.WriteLine("Message :" +e.Message);

                    }

 

                    catch (FormatException e)

                    {

                        Console.WriteLine("FormatExceptioncaught!!!");

                        Console.WriteLine("Source :" +e.Source);

                        Console.WriteLine("Message :" +e.Message);

                    }

 

                    catch (Exception e)

                    {

                        Console.WriteLine("Exceptioncaught!!!");

                        Console.WriteLine("Source :" +e.Source);

                        Console.WriteLine("Message :" + e.Message);

                    }

                }

                c2012 = null;

            }

            Console.WriteLine("***************************************");

            Console.WriteLine("*********Programcompleted.************");

            Console.WriteLine("***************************************");

 

            flag = true;

           //线程池是后台线程,主线程结束前需要等待副线程执行完成。

            while (flag)

            {

                ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);

                difference =nWorkerThreads - workerThreads;

                if (difference == 0)

                {

                    flag = false;

                }

                else

                {

                    Console.WriteLine("Wait for EXIT...");

                    Thread.Sleep(1000);

                }

            }

        }

 

上述提到ConnectedFeedback,它是封装Ping命令成功返回累计数据

classConnectedFeedback

    {

        publicIPAddress NetIPaddress;  // pingIP地址

        publicString PingStatus;       // 返回状态

        publicint PingStatusValue;     //返回状态成功计数

        publiclong RoundTripTime;      // 保存RoundTripTime平均值

        publicint TimeToLive;           // 保存TimeToLive平均值

        publicfloat rate;                // 计算成功率值

        publicint Connectivity;         //计算ping是否通

        publicint C2011ID;              // 数据库表C2011ID

 

        privatelong RoundTripTimePrivate;  //返回RoundTripTime

        privateint TimeToLivePrivate;       //返回TimeToLive

 

        public ConnectedFeedback(C2011 _c2011)

        {

            this.NetIPaddress = IPAddress.Parse(_c2011.IP);

            this.C2011ID = _c2011.id;

            this.PingStatus = null;

            this.RoundTripTime = 0;

            this.TimeToLive = 0;

            this.PingStatusValue = 0;

            this.rate = 0.0f;

            this.Connectivity = 2;

        }

 

        #region根据返回成功状态记录返回数据

        ///<summary>

        ///方法:根据状态记录ping返回数据

        ///</summary>

        ///<param>状态值,RoundTrip时间,TimeToLive值,缓冲区大小</param>

        ///<returns></returns>

        publicvoid PingFeedbackCalculate(PingReply reply)

        {

            if (PingStatusdeter(reply))

            {

                PingStatusValue++;

                RoundTripTime =RoundTripTime + RoundTripTimePrivate;

                TimeToLive =TimeToLive + TimeToLivePrivate;

            }

        }

        #endregion

 

//判断ping返回状态

        privatebool PingStatusdeter(PingReply reply)

        {

            if (reply.Status == IPStatus.Success)

            {

                RoundTripTimePrivate= reply.RoundtripTime;

                TimeToLivePrivate =reply.Options.Ttl;

                returntrue;

            }

            else

            {

                returnfalse;

            }

        }

//计算平均值的函数

        publicvoid Average(int totle)

        {

            if (PingStatusValue != 0)

            {

                RoundTripTime =RoundTripTime / PingStatusValue;

                TimeToLive =TimeToLive / PingStatusValue;

                rate = (float)PingStatusValue / totle;

                Connectivity = (rate> 0.33f) ? 1 : 2;

            }

        }

}

 

上述还提到WoodenStick,它是封装AutoResetEvent系统类和ConnectedFeedback自定义类,作为ping异步数据传递

classWoodenStick

    {

        publicAutoResetEvent AutoResetEventMembers { get; set; }

        publicConnectedFeedback ConnectedFeedbackMembers { get; set; }

        public WoodenStick(AutoResetEvent _Event, ConnectedFeedback _Feedback)

        {

            this.AutoResetEventMembers = _Event;

            this.ConnectedFeedbackMembers =_Feedback;

        }

}

 

C#的数据库对象

 

运行

 

 

问题,如果编译在.NETFramework 4.0以下版本,.Net垃圾回收机制不会回收内存,直到内存不足;如果编译在.NET Framework 4.0以上版本(包括.NET Framework 4.0),垃圾回收机制回收内存。

.NET Framework4.0截图


一个ping的小程序

  • 2008年03月24日 10:11
  • 8KB
  • 下载

超级 Ping 监测工具——为您的网络状态保驾护航

Ping 是一个网络命令,主要是用于确定本地主机是否能与另一台主机交换(发送与接收)数据。根据返回的信息,就可以推断 TCP/IP 参数是否设置得正确以及运行是否正常。正常情况下,Ping 将返回若干...
  • wangpeng198688
  • wangpeng198688
  • 2015年12月29日 19:09
  • 2855

QProcess调用外部ping程序实现网络状态检测

上代码: /* 作者:侯文斌 E-mail:houwenbin1986@gmail.com 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! */ #ifndef...
  • houwenbin1986
  • houwenbin1986
  • 2016年09月23日 17:14
  • 2009

C# 示例:检测网络连接

我们的应用程序的某些功能,可能需要一个互联网连接的运行时间测试。 一旦检测到互联网连接,可能会暂时被禁用的功能需要访问Internet和/或用户可以通过警报消息通知。 否则,应用程序可能会导致在操作过...
  • zhou__zhou
  • zhou__zhou
  • 2007年06月08日 21:16
  • 2881

详解Ping程序

ping程序编写的目的是为了测试另外一台主机是否可达。程序发送的是一份ICMP回显请求报文给目的主机,并等待ICMP回显应答。...
  • a5503308
  • a5503308
  • 2016年04月29日 00:37
  • 1636

如何写一个简单的ping程序

今天翻硬盘时,发现自己很久之前写的ping程序。突然想不如把ping程序放上来做一下也算让之前自己写的东西重见天日,当时还是花了挺多时间来写,感触良多。首先呢,ping用到的协议是网络层的ICMP协议...
  • chenpidaxia
  • chenpidaxia
  • 2017年09月02日 20:05
  • 1068

ping命令整个过程详解

转自:http://wanicy.blog.51cto.com/509018/335207/ 如果你想了解ping命令的原理,看了这篇文章,你会从对网络一窍不通,到豁然开朗。  ...
  • guoweimelon
  • guoweimelon
  • 2016年03月11日 23:32
  • 5789

Socket编程之ping程序的实现

ping程序的实现,网络协议分析,TCP/IP协议详解的课程设计,Socket网络编程
  • huangqiang1363
  • huangqiang1363
  • 2016年01月06日 19:28
  • 3173

ping程序的实现

关于网络编程,知之甚少,linux环境下编程的经验也比较缺乏,于是乎,在百度文库上下载了一个关于ping的程序设计,照着将代码敲打一遍,顺便熟悉某些东东。 敲完代码,运行时,发现错误极多,正好也试着学...
  • petershina
  • petershina
  • 2013年02月05日 14:05
  • 9211

自己写个ping程序玩玩---附带抓包

ping功能很常用, 在Windows/Linux上, 我们经常用ping功能来探测对方是否在线。 那么, ping到底是怎么实现的呢? 在本文中, 我们自己来写一个ping, 当然, 功能肯定没有W...
  • stpeace
  • stpeace
  • 2015年02月01日 18:59
  • 5459
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用ping方式探测网络连通性--一个小程序
举报原因:
原因补充:

(最多只允许输入30个字)