编写多线程网络检测程序的简单实现
作者:秋枫 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)。
有一大串。