Как добавить строки в datatable одновременно (многопоточность)
Я сделал IP-сканер, который содержит Backgroundworker для обработки процесса сканирования. Backgroundworker создает новые потоки, которые выполняли реальное сканирование для каждого IP-адреса...
Моя проблема заключается в том, что мне нужно собрать результаты сканирования для каждого IP-адреса, и эта коллекция должна быть потокобезопасной, особенно в письменной форме...
Код для моего Backgroundworker
Private Sub NwS_BackgroundWorker_DoWork(sender As Object, e As ComponentModel.DoWorkEventArgs) Handles NwS_BackgroundWorker.DoWork Dim toDoList As DataTable = e.Argument ' Progress Calculation Dim total As Int64 = NwS_ScanTotal(toDoList), current As Int64 = 0, progress As Int64 = 0 ' Test for a Network Connection Dim netStatus As Boolean = False, netInterfaces As String = "" For Each networkCard As NetworkInterface In NetworkInterface.GetAllNetworkInterfaces If networkCard.Name = "Ethernet" Or networkCard.Name = "WLAN" netInterfaces = netInterfaces & $" {networkCard.Name} : {networkCard.OperationalStatus.ToString}" If networkCard.OperationalStatus = OperationalStatus.Up Then netStatus = True End If Next If netStatus = False Dim messageBox = New Message_Box($"No Network Connection detected.{netInterfaces}", MetroColorStyle.Red) If messageBox.ShowDialog() = DialogResult.OK e.Cancel = True NwS_BackgroundWorker.CancelAsync() End If End If For Each ipRange As DataRow In toDoList.Rows Dim ipExport As IPAddress, endIp = Split(ipRange.Item(1), "."), startIp = Split(ipRange.Item(0), ".") ' Create a ThreadList Dim threadList As List(Of Thread) = New List(Of Thread) ' Scan all IPs For A As Int16 = startIp(0) To endIp(0) For B As Int16 = startIp(1) To endIp(1) For C As Int16 = startIp(2) To endIp(2) For D As Int16 = startIp(3) To endIp(3) ipExport = Net.IPAddress.Parse(A & "." & B & "." & C & "." & D) ' Report Progress current += 1 progress = current/ total * 100 NwS_BackgroundWorker.ReportProgress(progress, $"Scanning {ipExport}") ' Creating and starting new Background Thread Dim oThread As New Thread(AddressOf Me.NwS_PingHost) oThread.IsBackground = True threadList.Add(oThread) oThread.Start(ipExport) ' End Conditions If NwS_BackgroundWorker.CancellationPending e.Cancel = True Exit Sub End If Next ' Handbrake for decreasing CPU Usage NwS_BackgroundWorker.ReportProgress(progress, " ") NwS_Handbrake(threadList, False) threadList.Clear() Next Next Next Next GC.Collect End Sub
Сканирование Хоста добавление потоков данных
Private Sub NwS_PingHost(ByVal ipExport As IPAddress) ' Set NetworkScan Variables for Ping Request Dim status As String = "Unknown", hostName As String = " ", macImport As String = " ", macAddress As String = " " Dim ipLong As Int64 = IPtoLong(ipExport) Dim result As Net.NetworkInformation.PingReply Dim sendPing As New Net.NetworkInformation.Ping Try ' Try to send Ping Request result = sendPing.Send(ipExport, 120) If result.Status = Net.NetworkInformation.IPStatus.Success Then ' Resolve Hostname status = "Used" hostName = Net.Dns.GetHostEntry(ipExport).HostName 'Resolve Mac- Address Dim arp = New ArpRequest(ipExport) macImport = arp.GetResponse().ToString() If macImport <> Nothing Then macAddress = Regex.Replace(macImport, "(.{2})(.{2})(.{2})(.{2})(.{2})(.{2})", "$1:$2:$3:$4:$5:$6") End If Else status = "Free" hostName = "" End If ' Ping Exception: Non valid IP Catch ex As PingException status = "Unknown" ' Hostname Exception: IP resolving Error Catch ex As SocketException status = "Unknown" ' Hostname Exception: Non valid IP Catch ex As System.ArgumentException status = "Unknown" ' Mac Exceptions: (Arp Request) Catch ex As System.ComponentModel.Win32Exception If ex.NativeErrorCode = 67 Then status = "Used" macAddress = "--:--:--:--:--:--" ElseIf ex.NativeErrorCode = 111 Then status = "Used" macAddress = "--:--:--:--:--:--" ElseIf ex.NativeErrorCode = 31 Then status = "Used" macAddress = "--:--:--:--:--:--" ElseIf ex.NativeErrorCode = 87 Then status = "Used" macAddress = "--:--:--:--:--:--" ElseIf ex.NativeErrorCode = 1784 Then status = "Used" macAddress = "--:--:--:--:--:--" ElseIf ex.NativeErrorCode = 1168 Then status = "Used" macAddress = "--:--:--:--:--:--" End If Catch ex As Exception End Try ' Add results to DataGrid and remove Thread from List If status = "Used" Then NwSData.Rows.Add(My.Resources.Host, ipExport.ToString, hostName, macAddress, status, ipLong.ToString("D10")) ElseIf status = "Free" Then NwSData.Rows.Add(My.Resources.Free, ipExport.ToString, hostName, macAddress, status, ipLong.ToString("D10")) Else NwSData.Rows.Add(My.Resources.Unresolvable, ipExport.ToString, hostName, macAddress, status, ipLong.ToString("D10")) End If ' CleanUP ipExport = Nothing status = "" hostName = "" macImport = "" macAddress = "" End Sub
Что я уже пробовал:
Я создал DataTable Object = Unsafe for multithreading --> исключение в больших сканированиях "внутренний индекс поврежден '5'"
Я искал потокобезопасные методы для добавления строк или избегал этого исключения...
Источник данных должен быть привязан к DTGV, иначе загрузка всех результатов (например, 0.0.0.0 - 255.255.255.255) приведет к замораживанию или отмене программы...
У тебя есть какие-нибудь идеи?
Мои Источники Данных:
Public NwSData As DataTable = New DataTable("NwS_Log") Public NwSBinding As BindingSource = New BindingSource() ' Create NwS DataSource Private Sub NwS_DataSource() NwSData.Columns.Add("NwS_Column1", GetType(System.Drawing.Image)) NwSData.Columns.Add("NwS_Column2", GetType(String)) NwSData.Columns.Add("NwS_Column3", GetType(String)) NwSData.Columns.Add("NwS_Column4", GetType(String)) NwSData.Columns.Add("NwS_Column5", GetType(String)) NwSData.Columns.Add("NwS_Column6", GetType(String)) NwSBinding.DataSource = NwSdata NwS_Log.DataSource = NwSBinding NwS_Log.Columns(0).AutoSizeMode = DataGridViewAutoSizeColumnMode.None NwS_Log.Columns(0).HeaderText = "Status" NwS_Log.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.None NwS_Log.Columns(1).HeaderText = "IP Address" NwS_Log.Columns(2).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill NwS_Log.Columns(2).HeaderText = "Hostname" NwS_Log.Columns(3).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill NwS_Log.Columns(3).HeaderText = "Mac - Address" NwS_Log.Columns(4).Visible = False NwS_Log.Columns(4).HeaderText = "Status String" NwS_Log.Columns(5).Visible = False NwS_Log.Columns(5).HeaderText = "Bytes" ' Put each of the columns into programmatic sort mode. For Each column As DataGridViewColumn In NwS_Log.Columns column.SortMode = DataGridViewColumnSortMode.Programmatic Next End Sub