【问题标题】:Ping multiple device names (hostname) on the NetworkPing 网络上的多个设备名称(主机名)
【发布时间】:2021-05-06 12:18:24
【问题描述】:

DataGridView 在列索引0 处显示主机名,网络上的计算机/打印机名称。

pc1
pc2
print3
pc5
print
....

这样的名字有 500 多个。
我知道如何 ping 它们:

For i = 0 To DataGridView1.Rows.Count - 1
    Try
        If My.Computer.Network.Ping(DataGridView1.Item(0, i).Value) = True Then
            DataGridView1.Rows(i).DefaultCellStyle.BackColor = Color.Lime
        Else
            DataGridView1.Rows(i).DefaultCellStyle.BackColor = Color.Red
        End If
    Catch ex As Exception
        DataGridView1.Rows(i).DefaultCellStyle.BackColor = Color.Red
    End Try
Next

问题是 Ping 需要很长时间并且应用程序冻结。
如何加快此过程?
假设该节点不可用,则只需将其从列表中删除即可。

【问题讨论】:

标签: vb.net winforms datagridview ping


【解决方案1】:

使用 Ping 类提供的异步版本 Ping.SendPingAsync() 同时 Ping 多个地址的示例。
此版本是可等待的,与Ping.SendAsync() 方法不同,仍然是异步,但由事件驱动。

由于您使用 DataGridView 来存储 IpAddress/HostName 并呈现 PingReply 结果,因此您需要确定一种方法来匹配 Ping 结果与 Ip/Host 地址来自的 DataGridView 的正确单元格被拍了。
在这里,我将 Row 的索引传递给该方法,因此当 Ping 结果异步返回时,我们可以将响应匹配到 DataGridView 中的特定单元格。

为了使 initialization 方法更通用,我还传递了存储 Ip/主机地址的列的索引以及将显示结果的列的索引(您可以也只是传递所有索引,而不是对方法的 DataGridView 控件引用并以不同的方式处理结果)。

循环从 DataGridView 中提取地址并创建一个 List(Of Task),为找到的每个地址添加一个 PingAsync() 任务。
收集完成后,List(Of Task) 将传递给 Task.WhenAll() 方法,然后等待。
该方法启动列表中的所有Task,当所有Task都有结果时返回。

► 请注意,Ping 过程在此处将TimeOut 设置为5000ms,因此所有任务将在该时间间隔之前或之内返回,无论成功与否。
然后,您可以决定是否要重新安排失败的 Ping。

UI 更新使用Progress 委托处理。它只是一个在 Ping 过程有结果要显示时调用的方法(Action 委托)。
当更新 UI 的方法在不同的线程中运行时也可以使用它:Report() 方法将在创建委托的线程中调用 Progress 对象委托:UI 线程,这里(在示例中,我们是但实际上并没有离开它)。

这就是它的工作原理:


假设您从 Button.Click 事件处理程序开始 ping 序列。
请注意,处理程序声明为async

Private Async Sub btnMassPing_Click(sender As Object, e As EventArgs) Handles btnMassPing.Click
    Await MassPing(DataGridView1, 1, 2)
End Sub

初始化方法和IProgress<T>报告处理程序:

Imports System.Drawing
Imports System.Net.NetworkInformation
Imports System.Net.Sockets
Imports System.Threading.Tasks

Private Async Function MassPing(dgv As DataGridView, statusColumn As Integer, addressColumn As Integer) As Task
    Dim obj = New Object()
    Dim tasks = New List(Of Task)()

    Dim progress = New Progress(Of (sequence As Integer, reply As Object))(
            Sub(report)
                SyncLock obj
                    Dim status = IPStatus.Unknown
                    If TypeOf report.reply Is PingReply Then
                        status = DirectCast(report.reply, PingReply).Status
                    ElseIf TypeOf report.reply Is SocketError Then
                        Dim socErr = DirectCast(report.reply, SocketError)
                        status = If(socErr = SocketError.HostNotFound,
                            IPStatus.DestinationHostUnreachable,
                            IPStatus.Unknown)
                    End If

                    Dim color As Color = If(status = IPStatus.Success, Color.Green, Color.Red)
                    Dim cell = dgv(statusColumn, report.sequence)
                    cell.Style.BackColor = color
                    cell.Value = If(status = IPStatus.Success, "Online", status.ToString())
                End SyncLock
            End Sub)

    For row As Integer = 0 To dgv.Rows.Count - 1
        If row = dgv.NewRowIndex Then Continue For
        Dim ipAddr = dgv(addressColumn, row).Value.ToString()
        tasks.Add(PingAsync(ipAddr, 5000, row, progress))
    Next

    Try
        Await Task.WhenAll(tasks)
    Catch ex As Exception
        ' Log / report the exception
        Console.WriteLine(ex.Message)
    End Try
End Function

PingAsync工作者方法:

Private Async Function PingAsync(ipAddress As String, timeOut As Integer, sequence As Integer, progress As IProgress(Of (seq As Integer, reply As Object))) As Task
    Dim buffer As Byte() = New Byte(32) {}
    Dim ping = New Ping()

    Try
        Dim options = New PingOptions(64, True)
        Dim reply = Await ping.SendPingAsync(ipAddress, timeOut, buffer, options)
        progress.Report((sequence, reply))
    Catch pex As PingException
        If TypeOf pex.InnerException Is SocketException Then
            Dim socEx = DirectCast(pex.InnerException, SocketException)
            progress.Report((sequence, socEx.SocketErrorCode))
        End If
    Finally
        ping.Dispose()
    End Try
End Function

【讨论】:

    猜你喜欢
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多