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

         前段时间编写过一个简单的网络连接检测程序,功能就是检测某一个网段中的计算机跟本机的连接情况。小程序自己用还行,不过写的比较简单。

程序界面如下:

 备注:

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

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

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

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

using System;
using System.Diagnostics;

namespace ZZ
{
	/// <summary>
	/// PingCompleted事件委托
	/// </summary>
	public delegate void PingCompletedHandler(object sender,PingEventArgs e);
	/// <summary>
	/// PingCommand 的摘要说明。
	/// </summary>
	public class PingCommand
	{
		/// <summary>
		/// PingCompleted事件
		/// </summary>
		public event PingCompletedHandler PingCompleted;
		private string [] _ips;
		private Process _p;
		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="ips"></param>
		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";
		}
		/// <summary>
		/// 线程调用方法
		/// </summary>
		public void RunPings()
		{
			Ping(this._ips);
		}
		/// <summary>
		/// 执行ping命令
		/// </summary>
		/// <param name="ip"></param>
		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}}));
		}
		/// <summary>
		/// 事件处理
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected virtual void OnPingCompleted(object sender,PingEventArgs e)
		{
			if(PingCompleted != null)
				PingCompleted(sender,e);
		}
		/// <summary>
		/// 执行ping命令
		/// </summary>
		/// <param name="ips"></param>
		public void Ping(string [] ips)
		{
			foreach(string ip in ips)
				Ping(ip);
		}
	}
	/// <summary>
	/// 定义参数类
	/// </summary>
	public class PingEventArgs : EventArgs
	{
		private string [,] _pingResult;
		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="pingResult">Ping结果</param>
		public PingEventArgs(string [,] pingResult)
		{
			this._pingResult = pingResult;
		}
		/// <summary>
		/// Ping结果
		/// </summary>
		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();
		}
	}
}
描述:由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、付费专栏及课程。

余额充值