1、多线程在 Visual C#网络编程中的应用网络应用程序的一般都会或多或少的使用到线程,甚至可以说,一个功能稍微强大的网络应用程序总会在其中开出或多或少的线程,如果应用程序中开出的线程数目大于二个,那么就可以把这个程序称之为多线程应用程序。那么为什么在网络应用程序总会和线程交缠在一起呢?这是因为网络应用程序在执行的时候,会遇到很多意想不到的问题,其中最常见的是网络阻塞和网络等待等。程序在处理这些问题的时候往往需要花费很多的时间,如果不使用线程,则程序在执行时的就会表现出如运行速度慢,执行时间长,容易出现错误、反应迟钝等问题。而如果把这些可能造成大量占用程序执行时间的过程放在线程中处理,就往往能
2、够大大提高应用程序的运行效率和性能和获得更优良的可伸缩性。那么这是否就意味着应该在网络应用程序中广泛的使用线程呢?情况并非如此,线程其实是一把双刃剑,如果不分场合,在不需要使用的地方强行使用就可能会产生许多程序垃圾,或者在程序结束后,由于没有能够销毁创建的进程而导致应用程序挂起等问题。所以如果你认为自己编写的代码足够快,那我给你的建议还是别使用线程或多线程。这里要提醒诸位的是如果您对在 Windows 下的线程和其执行原理和机制还不十分清楚,可以先参阅一下介绍 Windows 操作系统方面的书籍,它们一般都会对其进行比较详细的阐述。然后再阅读本文。一、简介在 Visual C中创建和使用线程:
3、Visual C中使用的线程都是通过自命名空间 System.Threading 中的 Thread 类经常实例化完成的。通过 Thread 类的构造函数来创建可供 Visual C使用的线程,通过Thread 中的方法和属性来设定线程属性和控制线程的状态。以下 Thread 类中的最典型的构造函数语法,在 Visual C中一般使用这个构造函数来创建、初始化 Thread 实例。public Thread (ThreadStart start);参数:start ThreadStart 委托,它将引用此线程开始执行时要调用的方法。Thread 还提供了其他的构造函数来创建线程,这里就不一一介
4、绍了。表 01 是 Thread类中的一些常用的方法及其简要说明:方法 说明Abort 调用此方法通常会终止线程,但会引起 ThreadAbortException 类型异常。Interrupt 中断处于 WaitSleepJoin 线程状态的线程。Join 阻塞调用线程,直到某个线程终止时为止。ResetAbort 取消当前线程调用的 Abor 方法。Resume 继续已挂起的线程。Sleep 当前线程阻塞指定的毫秒数。Start 操作系统将当前实例的状态更改为 ThreadState.Running。Suspend 挂起线程,或者如果线程已挂起,则不起作用。表 01:Thread 类的常用
5、方法及其说明这里要注意的是在.Net 中执行一个线程,当线程执行完毕后,一般会自动销毁。如果线程没有自动销毁可通过 Thread 中的 Abort 方法来手动销毁,但同样要注意的是如果线程中使用的资源没有完全销毁,Abort 方法执行后,也不能保证线程被销毁。在 Thread 类中还提供了一些属性用以设定和获取创建的 Thread 实例属性,表 02 中是 Thread 类的一些常用属性及其说明:属性 说明CurrentCulture 获取或设置当前线程的区域性。CurrentThread 获取当前正在运行的线程。IsAlive 获取一个值,该值指示当前线程的执行状态。IsBackground
6、 获取或设置一个值,该值指示某个线程是否为后台线程。Name 获取或设置线程的名称。Priority 获取或设置一个值,该值指示线程的调度优先级。ThreadState 获取一个值,该值包含当前线程的状态。表 02:Thread 类的常用属性及其说明二、本文的主要内容及程序调试和运行环境:本文的主要内容是介绍多线程给用 Visual C编写网络应用程序带来的更高性能提高。具体的做法是在 Visual C用二种不同的方法,一种采用了多线程,另一种不是,来实现同一个具体网络应用示例,此示例的功能是获取网络同一网段多个 IP 地址对应的计算机的在线状态和对应的计算机名称,通过比较这二种方法的不同执行
7、效率就可知多线程对提高网络应用程序的执行效率是多么的重要了。以下是本文中设计到程序的调试和运行的基本环境配置:(1)微软公司视窗 2000 服务器版。(2)Visual Studio .Net 2002 正式版,.Net FrameWork SDK 版本号 3705。三、扫描网络计算机的原理:下面介绍的这个示例的功能是通过扫描一个给定区间 IP 地址,来判断这些 IP 地址对应的计算机是否在线,如果在线则获得 IP 地址对应的计算机名称。程序判断计算机是否在线的是采用对给定 IP 地址的计算机进行 DNS 解析,如果能够根据 IP 地址解析出对应的计算机名称,则说明此 IP 地址对应的计算机在
8、线;反之,如果解析不出,则会产生异常出错,通过对异常的捕获,得到此 IP 地址对应的计算机并不在线。为了更清楚地说明问题和便于掌握在 Visual C编写多线程网络应用程序的方法,本文首先介绍的是不基于多线程的网络计算机扫描程序的编写步骤,然后再在其基础上,把它修改成多线程的计算机扫描程序,最后比较这二个程序的执行效率,你就会发现线程在网络编程中的重要作用了。四、Visual C实现不基于多线程的网络计算机扫描程序以下是在 Visual C实现不基于多线程的网络计算机扫描程序步骤:1、启动 Visual Studio .Net,并新建一个 Visual C项目,项目名称为【扫描网络计算机】 。
9、2、把 Visual Studio .Net 的当前窗口切换到【Form1.cs(设计) 】窗口,并从【工具箱】中的【Windows 窗体组件】选项卡中往 Form1 窗体中拖入下列组件,并执行相应操作:四个 NumericUpDown 组件,用以组合成一个 IP 地址区间。一个 ListBox 组件,用以显示扫描后的结果。一个 ProgressBar 组件,用以显示程序的运行进度。四个 Label 组件,用以显示提示信息。一个 GroupBox 组件。一个 Button 组件,名称为 button1,并在这组件拖入窗体后,双击 button1,这样Visual Studio .Net 就会产
10、生这 button1 组件 Click 事件对应的处理代码。界面设置如下图:图 01:【扫描网络计算机】项目的设计界面3、把 Visual Studio .Net 的当前窗口切换到【Form1.cs】 ,进入 Form1.cs 文件的编辑界面。在 Form1.cs 头部,用下列代码替换系统缺省的导入命名空间代码:using System ;using System.Drawing ;using System.Collections ;using System.ComponentModel ;using System.Windows.Forms ;using System.Data ;using
11、 System.Net.Sockets ;using System.Net ;4、用下列代码替换 Form1.cs 中的 button1 的 Click 时间对应的处理代码,下列代码的功能是扫描给定的 IP 地址区间,并把扫描结果显示出来。private void button1_Click ( object sender , System.EventArgs e )listBox1.Items.Clear ( );/清楚扫描结果显示区域DateTime StartTime = DateTime.Now;/获取当前时间string mask = numericUpDown1.Value.ToS
12、tring ( ) + “.“ + numericUpDown2.Value.ToString ( ) + “.“ + numericUpDown3.Value.ToString ( ) + “.“;int Min = ( int ) numericUpDown4.Value;int Max = ( int ) numericUpDown5.Value;if ( Min Max )MessageBox.Show ( “输入的 IP 地址区间不合法,请检查!“ , “错误!“ );return;/判断输入的 IP 地址区间是否合法progressBar1.Minimum = Min;progre
13、ssBar1.Maximum = Max;int i;for ( i = Min; i 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
14、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 地址字符串mythreadk = new Thread ( new ThreadStart ( HostPing.scan ) );/初始化一个线程实例mythreadk.Start ( );/启动线程至此,【扫描网络计算机
15、】项目已经被修改成一个多线程的程序了,此时在运行程序,并且同样再扫描上面给定 IP 地址区间对应的计算机,就会惊奇的发现程序执行时间所建为10 秒了,并且不论要扫描的计算机数目有多少,程序的运行时间也是 10 秒左右,这是因为程序为扫描每一个 IP 都分配一个线程,这样程序的执行时间就不与要扫描的 IP 地址段中的 IP 地址数目有关联了,这样也就大大减少了程序的运行时间,提高了程序的运行效率,这也充分体现出多线程给网络编程带来的好处。图 03 也是程序扫描“10.138.198.1“至“10.138.198.10“这个 IP 地址区间计算机后的运行界面所示:图 03:基于多线程的【扫描网络计
16、算机】项目的运行界面通过对二个程序的比较可见,在编写网络应用程序中,正确的使用线程的确能够大大提高程序的运行效率。六、总结:至此,本节要介绍的内容就全部结束了,不知道诸位通过上面的介绍是否了解、掌握了下面几点:1、如何获取系统当前时间,和实现时间日期类型数据的加减。2、在编写网络应用程序时候,使用线程(多线程)的原因,以及线程(多线程)会给网络应用程序带来什么好处。3、如何在应用程序中创建多个线程实例。4、如何实现带“返回值“的线程。如果上述要点你都能够掌握,那是再好不过的了。但如果你对线程及其使用方法还感觉模糊,那也不要紧,毕竟线程在编程技术中是一个内容丰富,使用复杂的东东,要立马掌握的确是很困难的事情。在以后的文章中也将再介绍这方面的内容。