五.把【扫描网络计算机】程序修改成基于多线程的程序:
在修改成多线程程序之前,必须面对并解决下面几个问题:
1. 线程是无返回值的,所以在线程中处理、调用的应是一个过程,所以要把扫描IP地址对应的计算机的代码给包装成一个过程。
2. 放在线程中处理的过程,因为没有返回值,从而无法向主程序(进程)传递数值。但扫描IP地址对应的计算机的过程却要向主程序(进程)传递IP地址是否在线的数据,所以在修改成多线程程序之前,必须从线程往主程序(进程)传递数据的问题。
下面是在【扫描网络计算机】项目的基础上,把它修改成基于多线程程序的具体实现步骤:
1. 由于程序中使用到线程,所以在Form1.cs代码首部,导入命名空间代码区中加入下列代码,下列代码是导入Thread类所在的命名空间。
| using System.Threading ; |
2. 在Form1.cs代码的namespace代码区加入下列语句,下列语句是定义一个delegate:
| public delegate void UpdateList ( string sIP , string sHostName ) ; |
3. 在Form1.cs中的定义Form1的class代码区定义加入下列代码,下列代码是定义一个变量,用以存放程序执行的时间:
| private System.DateTime StartTime ; |
4. 在Form1.cs代码的Main函数之后,添加下列代码,下列代码是创建一个名称为ping的Class,这个Class能够通过其设定的属性接收给定的IP地址字符串,并据此来判断此IP地址字符串对应的计算机是否在线,并通过其设定的HostName属性接收从线程传递来的数据。
| public class ping { public UpdateList ul ; public string ip ; //定义一个变量,用以接收传送来的IP地址字符串 public string HostName ; //定义一个变量,用以向主进展传递对应IP地址是否在线数据 public void scan ( ) { IPAddress myIP = IPAddress.Parse ( ip ) ; try { IPHostEntry myHost = Dns.GetHostByAddress ( myIP ); HostName = myHost.HostName.ToString ( ) ; } catch { HostName = "" ; } if (HostName == "") HostName = " 主机没有响应!"; if ( ul != null) ul ( ip , HostName ) ; } //定义一个过程(也可以看出为方法),用以判断传送来的IP地址对应计算机是否在线 } |
5. 在Form1.cs中添加完上述代码后,再添加下列代码:
| void UpdateMyList ( string sIP , string sHostName ) { lock ( listBox1 ) { listBox1.Items.Add ( sIP + " " + sHostName ) ; if ( progressBar1.Value != progressBar1.Maximum ) { progressBar1.Value++ ; } if ( progressBar1.Value == progressBar1.Maximum ) { MessageBox.Show ( "成功完成检测!" , "提示" ) ; DateTime EndTime = DateTime.Now ; TimeSpan ts = EndTime-StartTime ; label4.Text = ts.Seconds.ToString ( ) + "秒" ; //显示扫描计算机所需要的时间 progressBar1.Value = progressBar1.Minimum ; } } } |
6. 用下列代码替换Form1.cs中button1的Click事件对应的处理代码,下列代码功能是创建多个扫描给定IP地址区间对应的计算机线程实例,并显示扫描结果。
| private void button1_Click(object sender, System.EventArgs e) { listBox1.Items.Clear ( ) ; //清楚扫描结果显示区域 StartTime = DateTime.Now ; //获取当前时间 string mask = numericUpDown1.Value.ToString ( ) + "." + numericUpDown2.Value.ToString ( ) + "." + numericUpDown3.Value.ToString ( ) + "." ; int Min = ( int ) numericUpDown4.Value ; int Max = ( int ) numericUpDown5.Value ; if ( Min > Max ) { MessageBox.Show ( "输入的IP地址区间不合法,请检查!" , "错误!" ) ; return ; } //判断输入的IP地址区间是否合法 int _ThreadNum = Max - Min + 1 ; Thread[] mythread = new Thread [ _ThreadNum ] ; //创建一个多个Thread实例 progressBar1.Minimum = Min ; progressBar1.Maximum = Max + 1 ; progressBar1.Value = Min ; int i ; for (i = Min ; i <= Max ; i++ ) { int k = Max - i ; ping HostPing = new ping ( ) ; //创建一个ping实例 HostPing.ip = mask + i.ToString ( ) ; HostPing.ul = new UpdateList ( UpdateMyList ) ; //向这个ping实例中传递IP地址字符串 mythread[k] = new Thread ( new ThreadStart ( HostPing.scan ) ) ; //初始化一个线程实例 mythread[k].Start ( ) ; //启动线程 } } |
至此,【扫描网络计算机】项目已经被修改成一个多线程的程序了,此时在运行程序,并且同样再扫描上面给定IP地址区间对应的计算机,就会惊奇的发现程序执行时间所建为10秒了,并且不论要扫描的计算机数目有多少,程序的运行时间也是10秒左右,这是因为程序为扫描每一个IP都分配一个线程,这样程序的执行时间就不与要扫描的IP地址段中的IP地址数目有关联了,这样也就大大减少了程序的运行时间,提高了程序的运行效率,这也充分体现出多线程给网络编程带来的好处。图03也是程序扫描"10.138.198.1"至"10.138.198.10"这个IP地址区间计算机后的运行界面所示:

图03:基于多线程的【扫描网络计算机】项目的运行界面
通过对二个程序的比较可见,在编写网络应用程序中,正确的使用线程的确能够大大提高程序的运行效率。
六.总结:
至此,本节要介绍的内容就全部结束了,不知道诸位通过上面的介绍是否了解、掌握了下面几点:
1. 如何获取系统当前时间,和实现时间日期类型数据的加减。
2. 在编写网络应用程序时候,使用线程(多线程)的原因,以及线程(多线程)会给网络应用程序带来什么好处。
3. 如何在应用程序中创建多个线程实例。
4. 如何实现带"返回值"的线程。
如果上述要点你都能够掌握,那是再好不过的了。但如果你对线程及其使用方法还感觉模糊,那也不要紧,毕竟线程在编程技术中是一个内容丰富,使用复杂的东东,要立马掌握的确是很困难的事情。在以后的文章中也将再介绍这方面的内容。
