编写多线程网络检测程序的简单实现

编写多线程网络检测程序的简单实现

作者:秋枫 2004-7-8

         前段时间编写过一个简单的网络连接检测程序,功能就是检测某一个网段中的计算机跟本机的连接情况。小程序自己用用感觉还行,不过写的比较简单,没有什么特殊的功能也就没有放到BLOG上。最近看到CSDN论坛中有网友提及这方面的问题,所以把程序搬了出来,望能给那些需要的网友带来些许帮助。

程序的整个界面如下:

 

备注:

TextBox:用来输入一个C类的网段;

NumericUpDown:用来选择网段内的IP范围;

NumericUpDown3:用来选择一个线程最多处理的IP数量。

整个程序的一个主要类就是PingCommand类,如果要采用套接字实现可以参考孟子e一篇文章

using System;

using System.Diagnostics;

 

namespace ZZ

{

     ///

     /// PingCompleted事件委托

     ///

     public delegate void PingCompletedHandler(object sender,PingEventArgs e);

     ///

     /// PingCommand 的摘要说明。

     ///

     public class PingCommand

     {

         ///

         /// PingCompleted事件

         ///

         public event PingCompletedHandler PingCompleted;

         private string [] _ips;

         private Process _p;

         ///

         /// 构造函数

         ///

         ///

         public PingCommand(string [] ips)

         {

              this._ips = ips;

              this._p = new Process();

              this._p.StartInfo.UseShellExecute = false;

              this._p.StartInfo.RedirectStandardInput = true;

              this._p.StartInfo.RedirectStandardOutput = true;

              this._p.StartInfo.RedirectStandardError = true;

              this._p.StartInfo.CreateNoWindow = true;

              this._p.StartInfo.FileName = "cmd.exe";

         }

         ///

         /// 线程调用方法

         ///

         public void RunPings()

         {

              Ping(this._ips);

         }

         ///

         /// 执行ping命令

         ///

         ///

         public void Ping(string ip)

         {

              _p.Start();

              _p.StandardInput.WriteLine("ping -n 1 "+ip);

              _p.StandardInput.WriteLine("exit");

              string strRst = _p.StandardOutput.ReadToEnd();

              _p.Close();

              if(strRst.IndexOf("(0% loss)")!=-1)

                   strRst = "连接";

              else if(strRst.IndexOf("Request timed out.")!=-1)

                   strRst = "超时";

              else if(strRst.IndexOf("Destination host unreachable.")!=-1)

                   strRst = "无法到达目的主机";

              else if(strRst.IndexOf("Unknown host")!=-1)

                   strRst = "无法解析主机";

              OnPingCompleted(this,new PingEventArgs(new string [,]{{ip,strRst}}));

         }

         ///

         /// 事件处理

         ///

         ///

         ///

         protected virtual void OnPingCompleted(object sender,PingEventArgs e)

         {

              if(PingCompleted != null)

                   PingCompleted(sender,e);

         }

         ///

         /// 执行ping命令

         ///

         ///

         public void Ping(string [] ips)

         {

              foreach(string ip in ips)

                   Ping(ip);

         }

     }

     ///

     /// 定义参数类

     ///

     public class PingEventArgs : EventArgs

     {

         private string [,] _pingResult;

         ///

         /// 构造函数

         ///

         /// Ping结果

         public PingEventArgs(string [,] pingResult)

         {

              this._pingResult = pingResult;

         }

         ///

         /// Ping结果

         ///

         public string[,] PingResult

         {

              get{return this._pingResult;}

         }

 

     }

}

上面PingEventArgs类为EventArgs的继承类,用来传递执行Ping命令的结果。还有上面public void Ping(string ip)方法里面的判断不是完全的,调用的shell命令为“ping  -n 1 ipaddress”,具体可以参考相关文章,这里有一个需要注意的是定义了一个Process类成员变量,在构造函数中进行实例化然后就是重复使用,如果是在每次调用Ping方法时都实例化一个Process类就会变得很慢。

另一个就是窗体类了,里面用一个ArrayList来保存线程对象,下面是主要代码:

 

namespace ZZ

{

     public class FormMain : System.Windows.Forms.Form

     {

         //委托

         private delegate void UpdateListViewHandler(string[,] pingResult);

         private ArrayList ThreadArray;//用来保存线程

         private DateTime startTime;//检测起始时间

         private int hostCount;//IP数量

……

//构造函数

public FormMain()

{

              InitializeComponent();

              this.labelLocal.Text = "本地主机:"+Environment.MachineName;

              this.ThreadArray = new ArrayList();

         }

         ///运行按钮执行函数,用来启动网络检测

         private void buttonPing_Click(object sender, System.EventArgs e)

         {

              this.listView1.Items.Clear();

              this.labelTime.Text = String.Empty;

              int start = (int)this.numericUpDownStart.Value;

              int end = (int)this.numericUpDownEnd.Value;

              this.hostCount = end-start+1;

              string cAddress = this.textBox1.Text.Substring(0,this.textBox1.Text.LastIndexOf("."));

              ArrayList ipsList = new ArrayList();

              for(int i=start;i<=end;i++)

              {

                   ipsList.Add( String.Format(cAddress+".{0}",i));

              }

              string [] ips = (string[])ipsList.ToArray(typeof(string));

 

              if(ips != null && ips.Length>0)

              {

                   this.buttonPing.Enabled = false;

                   this.startTime = DateTime.Now;

                  

                   int arrayLenth = (int)this.numericUpDownMax.Value;//一个线程执行的IP

                   int threadCount = (int)Math.Floor(ips.Length/arrayLenth);//计算线程的数量,如果为0,计算余数

                   this.ThreadArray.Clear();

                   Thread PingThread = null;

                   string[] newIps = null;

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

                   {

                       newIps = new string[arrayLenth];

                       Array.Copy(ips,i*arrayLenth,newIps,0,arrayLenth);

 

                       PingCommand pingCommand = new PingCommand(newIps);

                       PingThread = new Thread(new ThreadStart(pingCommand.RunPings));

                       pingCommand.PingCompleted += new PingCompletedHandler(pingCommand_PingCompleted);

                       this.ThreadArray.Add(PingThread);

                       PingThread.Start();

                   }

                   int endCount = (ips.Length%arrayLenth);//计算余数

                   if(endCount>0)

                   {

                       newIps = new string[endCount];

                       Array.Copy(ips,ips.Length-endCount-1,newIps,0,endCount);

                        PingCommand pingCommand = new PingCommand(newIps);

                       PingThread = new Thread(new ThreadStart(pingCommand.RunPings));

                       pingCommand.PingCompleted +=new PingCompletedHandler(pingCommand_PingCompleted);

                       this.ThreadArray.Add(PingThread);

                       PingThread.Start();

                   }

                   this.labelThreadCount.Text = "线程数:"+this.ThreadArray.Count.ToString();

              }

         }

         //更新信息显示,Invoke异步调用

         private void pingCommand_PingCompleted(object sender,PingEventArgs e)

         {

              this.listView1.BeginInvoke(new UpdateListViewHandler(MessageInfoShow),new object[]{e.PingResult});

         }

         //更新ListView

         private void MessageInfoShow(string[,] pingResult)

         {

              this.listView1.Items.Insert(0,new ListViewItem(new string []{pingResult[0,0],pingResult[0,1]}));

              if(this.listView1.Items.Count ==this.hostCount)

              {

                   this.listView1.Refresh();

                   TimeSpan ts = (TimeSpan)(DateTime.Now-this.startTime);

                   this.labelTime.Text = "检测时间:"+ts.TotalSeconds.ToString()+"";

                   this.buttonPing.Enabled = true;

              }

         }

                   //退出程序

         private void buttonExit_Click(object sender, System.EventArgs e)

         {

              Application.Exit();

         }

     }

}//命名空间

 

这里看了线程执行完后的输出信息

线程 '<无名称>' (0x1538) 已退出,返回值为 0 (0x0)

有一大串。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
描述:由C#编写多线程异步抓取网页的网络爬虫控制台程序 功能:目前只能提取网络链接,所用的两个记录文件并不需要很大。网页文本、图片、视频和html代码暂时不能抓取,请见谅。 但需要注意,网页的数目是非常庞大的,如下代码理论上大概可以把整个互联网网页链接都抓下来。 但事实上,由于处理器功能和网络条件(主要是网速)限制,一般的家用电脑最多能胜任12个线程左右的抓取任务,抓取速度有限。可以抓取,但需要时间和耐心。 当然,这个程序把所有链接抓下来是可能的,因为链接占系统空间并不多,而且有记录文件的帮助,已抓取网页的数量可以堆积下去, 甚至可以把所有的互联网网络链接都存取下来,当然,最好是分批次。建议设置maxNum为500-1000左右,慢慢累积下去。 另外因为是控制台程序,有时候显示字符过多会系统会暂停显示,这时候只要点击控制台按下回车键就可以了。程序假死的时候,可以按回车键(Enter)试试。 /// 使用本程序,请确保已创建相应的记录文件,出于简化代码的考虑,本程序做的并不健壮,请见谅。 /// 默认的文件创建在E盘根目录“已抓取网址.txt”和“待抓取网址.txt”这两个文本文件中,使用者需要自行创建这两个文件,注意后缀名不要搞错。 这两个文件里面的链接基本都是有效链接,可以单独处理使用。 本爬虫程序的速度如下: 10线程最快大概500个链接每分钟 6-8线程最快大概400-500个链接每分钟 2-4线程最快大概200-400个链接每分钟 单线程最快大概70-100个链接每分钟 之所以用多线程异步抓取完全是出于效率考虑,本程序多线程同步并不能带来速度的提升,只要抓取的网页不要太多重复和冗余就可以,异步并不意味着错误。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值