利用多线程技术实现局域网快速扫描

摘要:大家知道,无论Windows9x,还是Windows2000/Xp,在关闭计算机后,其它计算机在短时间内仍然能够看到该计算机名称,所以通过网上邻居获取的局域网计算机并不十分准确。为了及时查看局域网内在线的计算机,本文将制作一个实用的局域网扫描工具,并示范VB2005中多线程编程技术。

【编程分析】

VB2005中的System.Net命名空间为当前网络上使用的多种协议提供了简单的编程接口,其中的Dns静态类,可从Internet域名系统(DNS)检索关于特定主机的信息,该类常用的属性和方法如下:

GetHostName:获取本地计算机的主机名;
GetHostByName:获取指定DNS主机名的DNS信息,其AddressList.GetValue(0)属性返回IP地址;
GetHostByAddress:获取指定IP地址的DNS主机信息;其HostName属性返回计算机名称;
要使用System.Net命名空间,需要先引入,代码如下:
Imports System.Net

一、获取网段

在局域网内,只通过交换机而不通过路由器的计算机必须在同一个网段,否则就无法进行相互通讯,比如IP地址为192.168.0.*(*代表1~254)的计算机只需要通过交换机就可以相互通讯。我们今天制作的这个程序,目的就是通过自动获取本机IP确定网段,然后对同网段的计算机进行扫描。获取本机IP,先通过DNS类的GetHostName方法获取机器名,然后通过GetHostByName方法获取IP地址,最后提取网段IP值,核心代码如下:

Dim IpTxt As String '网段
Private Sub Form1_Load()
Dim IpAddr As IPAddress
Dim IP,HostName As String
'获取本机名称
HostName = Dns.GetHostName
'获取本机IP地址
IpAddr=Dns.GetHostByName(HostName).AddressList.GetValue(0)
IP=IpAddr.ToString
'提取网段Ip
Dim P As Integer
'反向查找,取出IP前三位
P=InStrRev(IP,".",-1,vbTextCompare)
IpTxt=Microsoft.VisualBasic.Left(IP,P)
End Sub

二、扫描网内计算机

在得到网段后,我们就可以扫描网段内的编号为1~254的计算机了。在VB2005中,My.Computer.Network对象的Ping方法可以判断是否能与远程计算机通讯,当Ping成功后,调用DNS类的GetHostByAddress方法获取计算机名称,并将IP和名称保存到数组中,核心代码如下:

Dim Ip_Name(254,1) As String '扫描信息
Private Sub ScanLan(ByVal _Start As Integer, ByVal _End As Integer)
'参数范围判断,代码略
Dim cIp, cName As String
'逐个IP检查
For I As Integer = _Start To _End
cIp = IpTxt & I.ToString 'IP
'通过Ping方法检测IP
If My.Computer.Network.Ping(cIp) Then
Try '获取IP对应的机器名
cName=Dns.GetHostByAddress(cIp).HostName
'以上方法返回的机器名称可能出现“80.101.168.192.in-addr.arpa”机器名不准确的情况,下面的代码重新获取机器名,直到不包含“in-addr”等信息
While InStr(cName,"in-addr")>0
cName=Dns.GetHostByAddress(cIp).HostName
End While
'保存IP和名称
Ip_Name(I,0)=cIp
Ip_Name(I,1)=cName
Catch ex As Exception
End Try
End If
Next
End Sub
通过以上分析和代码,我们就可以扫描局域网中的计算机了,调用方法为:ScanLan(1,254),这里扫描了254个IP,如果要扫描部分IP,只需调整其IP值,如要扫描前100个IP,调用方法为:ScanLan(1,100)。在扫描计算机后,我们需要显示在线的计算机名称,下面的代码把数组中的在线计算机名称添加到列表框中:

Sub LoadName()
ListBox1.Items.Clear()
For i As Integer=1 To 254
If Ip_Name(i,1) <> "" Then
'IP和名称之间用Tab符分开
ListBox1.Items.Add(Ip_Name(i,0) & ControlChars.Tab & Ip_Name(i,1))
End If
Next
End Sub

面的方法有个明显的缺陷,那就是速度问题,当扫描的IP对应的计算机没开机或不存在时,扫描时间需要1~2秒,这样的速度扫描整个网段需要好几分钟。下面我们通过多线程技术实现快速扫描。

三、多线程扫描局域网

线程是进程的组成部分。进程中的线程可以同时执行,所以,采用多线程处理同一个问题,可以缩短处理时间。每个线程都有优先级,在较高优先级的线程完成任务的时候,较低优先级的线程可能会被迫等待。每个进程启动时都具有一个线程,该线程称为主线程。任何线程都可创建其他线程,进程中的所有线程共享该进程的地址空间。

在VB2005中,System.Threading命名空间提供一些使得可以进行多线程编程的类和接口,其中的Thread类用于创建并控制线程,设置其优先级并获取其状态,通过Start方法执行线程,通过IsAlive 属性获取当前线程的执行状态。需要说明的是,Thread类不可以用来访问其它进程的线程,它只可以用来创建一个线程而已。

本程序在设计上,可让用户选择线程数量,以便通过程序运行观察线程越多执行速度越快的效果,线程数量存放在ComboBox1中,初始化代码如下:

ComboBox1.Items.Add("5")
ComboBox1.Items.Add("51")
ComboBox1.Items.Add("127")
ComboBox1.Items.Add("254")
'共4种线程,默认127个线程
ComboBox1.SelectedIndex = 2
要使用线程,必须引入命名空间,代码如下:
Imports System.Threading

由于采用多线程扫描254个IP,在创建多线程时,我们需要指定每个线程扫描的IP段(起、止IP),当确定开始IP号StartIp后,结束IP号可以通过StartIp+255/Thrds-1计算得到。下面定义了一个过程ScanIp(),用于在创建线程时调用ScanLan()函数进行扫描,核心代码如下:

Dim StartIp As Integer '线程开始IP
Dim Thrds As Integer=127 '线程数
Dim Thrd() As Thread '线程对象
Private Sub ScanIp()
ScanLan(StartIp,StartIp+255/Thrds-1)
End Sub

下面的代码记录线程数,并重新定义线程

Private Sub ComboBox1_SelectedIndexChanged(…)…
Thrds=Val(ComboBox1.SelectedItem.ToString) '线程数量
ReDim Thrd(Thrds-1) '重新定义线程对象
End Sub

创建线程时,使用AddressOf运算符创建一个指向由ProcedureName指定的函数委托。如果指定的过程是实例方法,则此函数委托同时引用此实例和方法。接着,调用此函数委托时,将调用指定实例的指定方法。实现多线程扫描局域网,首先创建多个线程并执行,等待所有线程结束之后,装入扫描到的计算机到列表框,编程方法和核心代码如下:

Private Sub Button1_Click(…)…
'控件状态设置,代码略
'清空Ip_Name()数组,代码略
For T As Integer=0 To Thrds-1
'线程开始地址
StartIp=T*(255/Thrds)+1
'创建线程
Thrd(T)=New Thread(AddressOf ScanIp)
Thrd(T).Start() '启动线程
Next
'等待所有线程结束
Dim ThrEnd As Boolean
While ThrEnd = False
Application.DoEvents()
ThrEnd=True '假设都结束
For i As Integer=0 To Thrds-1
If Thrd(i).IsAlive Then
ThrEnd=False '未结束
Exit For
End If
Next
End While
LoadName() '装入名称
End Sub
四、保存扫描结果

通过System.IO命名空间中的StreamWriter对象创建文件并向文件中写入信息,保存的默认文件名取当前系统日期按“y-m-d-h-m-s”格式命名,保存的路径通过SaveFileDialog对话框设置,核心代码如下:

Imports System.IO '引入
Private Sub Button2_Click(…)…
'保存文件名
Fn = Now.Year & … & Now.Second & ".txt"
'打开保存对话框
SFD.FileName = Fn '默认
If SFD.ShowDialog Then
'初始化一个文件的StreamWriter实例
Dim SW As New StreamWriter(Fn)
'写入扫描结果到文件
For K = 0 To ListBox1.Items.Count-1
ListBox1.SelectedIndex=K
SW.WriteLine(ListBox1.SelectedItem.ToString)
Next
SW.Close() '关闭
End If
End Sub

【编程实现】

启动VB2005,新建应用程序项目,向窗体添加控件,合理布局,并完善程序代码,程序运行结果如图所示,调试环境:WinXp+VB2005,源码下载地址:http://family1.chinaok.com/down/200633/code.rar

【编程后记】

本文通过多线程技术实现了局域计算机的快速扫描,并返回IP和对应的机器名称,笔者在程序调试中发现:在多线程中,通过Ping方法检测IP不是100%准确,通过GetHostByAddress方法获取的机器名偶尔为空,因此,扫描中有“漏网之鱼”的情况,但是不会扫描到不在线的计算机。如果不采用多线程,本文的方法可以准确扫描到每一个在线的计算机,至于什么原因,还需要读者朋友们思考!另外,通过IP或者机器名获取计算机的其它信息,如网卡Mac地址,也是值得继续研究的!
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值