IP-Scanner

    • VB.NET

    Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von erbse.

      Hi Leute,
      hier mal ein Beispiel, wie man einen einfachen IP-Scanner realisieren könnte. (Konsolenanwendung)

      Angucken und lernen, bitte kein C&P. ;D
      Wenn ich euch viel geholfen habe, könnt Ihr mich ja in einem Programm erwähnen oder Ähnliches. Der Code ist jedenfalls frei verfügbar und liegt unter der WTFPL. Mit anderen (deutschen) Worten: Macht damit, was Ihr wollt.

      Er ist verbesserungswürdig, läuft aber einigermaßen gut.

      Hier der Code (OOP, benutzt VB2010-Compiler (z.B. bei den inline Properties)):
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Option Strict On
      2. Module SimpleScanner
      3. Dim WithEvents __Scanner As NetworkScanner
      4. Dim __IPs As List(Of NetworkScanner.PingResult)
      5. Sub Main()
      6. Dim abc As String = "192.168.1"
      7. Console.Title = "Simpler IPScanner"
      8. Console.WriteLine("Simpler IP-Scanner.")
      9. Console.WriteLine()
      10. Dim args As String() = Environment.GetCommandLineArgs()
      11. If args.Length > 1 Then
      12. Dim abc_ As String = FilterMask(args(1))
      13. If abc_ <> "-1" Then
      14. abc = abc_
      15. Console.WriteLine("Benutze Adressbereich aus Kommandozeile: {0}", abc)
      16. Else
      17. Console.WriteLine("Der Adressbereich der Kommandozeilenargumente konnte nicht validiert werden.")
      18. Console.WriteLine("Benutze standard Adressbereich: {0}", abc)
      19. End If
      20. Else
      21. Console.WriteLine()
      22. Console.WriteLine("Bitte geben Sie die ersten drei Teile der IP-Adresse an. (z.B. 192.168.178)")
      23. Dim input As String = Console.ReadLine().Trim
      24. If input = String.Empty Then
      25. Console.WriteLine("Keine Eingabe entdeckt.")
      26. Console.WriteLine("Benutze standard Adressbereich: {0}", abc)
      27. Else
      28. Dim abc_ As String = FilterMask(input)
      29. If abc_ <> "-1" Then
      30. abc = abc_
      31. Console.WriteLine("Benutze eingegebenen Adressbereich: {0}", abc)
      32. Else
      33. Console.WriteLine("Der Adressbereich konnte nicht validiert werden.")
      34. Console.WriteLine("Benutze standard Adressbereich: {0}", abc)
      35. End If
      36. End If
      37. End If
      38. Console.WriteLine()
      39. Console.WriteLine(" Folgende IPs sind erreichbar:")
      40. Console.WriteLine()
      41. Console.WriteLine(" ### AAA.BBB.CCC.DDD - Hostname - Pingzeit")
      42. __Scanner = New NetworkScanner(abc)
      43. __Scanner.Scan()
      44. While __Scanner.IsScanning : End While
      45. Dim s As String = Console.ReadLine()
      46. s = s.Trim
      47. If IsNumeric(s) Then
      48. Dim nummer As Integer = Integer.Parse(s)
      49. Dim ip_arr As NetworkScanner.PingResult() = __IPs.ToArray
      50. If nummer <= ip_arr.Length - 1 Then
      51. My.Computer.Clipboard.SetText(ip_arr(nummer).IP)
      52. Console.WriteLine("Die IP-Adresse ""{0}"" wurde in Ihre Zwischenablage kopiert.", ip_arr(nummer))
      53. End If
      54. ElseIf s = "a" Then
      55. Dim Result_arr As NetworkScanner.PingResult() = __IPs.ToArray
      56. Dim IP_Only_arr(__IPs.Count - 1) As String
      57. Dim zaehler As Integer = 0
      58. For Each result As NetworkScanner.PingResult In __IPs
      59. IP_Only_arr(zaehler) = result.IP
      60. zaehler += 1
      61. Next
      62. Dim clip As String = Join(IP_Only_arr, Environment.NewLine)
      63. My.Computer.Clipboard.SetText(clip)
      64. Console.WriteLine("Die IP-Adressen wurden in Ihre Zwischenablage kopiert.")
      65. End If
      66. End Sub
      67. Friend Function FilterMask(ByVal input As String) As String
      68. Dim pt As String = "\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
      69. Dim m As System.Text.RegularExpressions.Match = System.Text.RegularExpressions.Regex.Match(input, pt)
      70. If m.Captures.Count <> 1 Then
      71. Return "-1"
      72. Else
      73. Return m.Value
      74. End If
      75. End Function
      76. Private Sub __Scanner_ScanComplete(ByVal AvailabeIPs As System.Collections.Generic.List(Of NetworkScanner.PingResult)) Handles __Scanner.ScanComplete
      77. __IPs = AvailabeIPs
      78. Dim _Counter As Integer = 0
      79. For Each PingResult As NetworkScanner.PingResult In __IPs
      80. Console.WriteLine(" {0,-3} {1,-15} - {2,-20} - {3}ms", _Counter, PingResult.IP, PingResult.Hostname, PingResult.ElapsedTime)
      81. _Counter += 1
      82. Next
      83. Console.WriteLine()
      84. Console.WriteLine()
      85. Console.WriteLine("Scannen fertig.")
      86. Console.WriteLine()
      87. If _Counter > 0 Then
      88. Console.WriteLine("'a' zum Kopieren aller IPs.")
      89. Console.WriteLine("Eine Nummer, um eine bestimmte zu kopieren")
      90. Else
      91. Console.WriteLine("Es wurden keine IPs gefunden.") 'Unwahrscheinlich, da normalerweise mindestens der Localhost im Netz ist ^^
      92. 'Man kann aber nie wissen.
      93. End If
      94. End Sub
      95. End Module
      96. Friend Class NetworkScanner
      97. protected __MaxThreads as Integer = 20
      98. protected __CurrentThreads As Integer = 0
      99. Public Property MaxThreads() As Integer
      100. get
      101. return __MaxThreads
      102. end get
      103. set (value as integer)
      104. __MaxThreads = value
      105. end set
      106. end property
      107. Public Property CurrentThreads() As Integer
      108. get
      109. return __CurrentThreads
      110. end get
      111. set (value as integer)
      112. __CurrentThreads= value
      113. end set
      114. end property
      115. Protected __Subnet As String
      116. Protected __IPList As New List(Of PingResult)
      117. Protected __ResultCounter As Integer
      118. Public ReadOnly Property IPList As List(Of PingResult)
      119. Get
      120. Return __IPList
      121. End Get
      122. End Property
      123. Public ReadOnly Property Subnet As String
      124. Get
      125. Return __Subnet
      126. End Get
      127. End Property
      128. Public ReadOnly Property IsScanning As Boolean
      129. Get
      130. Return __ResultCounter < 255
      131. End Get
      132. End Property
      133. Public Event ScanComplete(ByVal AvailabeIPs As List(Of PingResult))
      134. Public Sub New(ByVal Subnet As String)
      135. __Subnet = Subnet
      136. End Sub
      137. Public Sub Scan()
      138. For d As Integer = 0 To 255 Step 1
      139. Dim ping As New IPPinger(Me, String.Format("{0}.{1}", __Subnet, d))
      140. AddHandler ping.GotPingResult, AddressOf GotPingResult
      141. ping.StartPing()
      142. Next
      143. End Sub
      144. Private Sub GotPingResult(ByVal sender As NetworkScanner, ByVal e As PingResult)
      145. If e.Successful Then
      146. 'Man könnte auch die nicht erfolgreichen adden, mache ich hier aber nicht, weil wir nur die erfolgreichen haben wollen ;)
      147. __IPList.Add(e)
      148. End If
      149. __ResultCounter += 1
      150. If __ResultCounter > 255 Then
      151. RaiseEvent ScanComplete(__IPList)
      152. End If
      153. End Sub
      154. Friend Structure PingResult
      155. Dim IP As String
      156. Dim Successful As Boolean
      157. Dim ElapsedTime As Long
      158. Dim Hostname As String
      159. Dim TimeOut As Integer
      160. Friend Sub New(ByVal _IP As String, ByVal _Successful As Boolean, ByVal _ElapsedTime As Long, ByVal _Hostname As String, ByVal _TimeOut As Integer)
      161. IP = _IP
      162. Successful = _Successful
      163. ElapsedTime = _ElapsedTime
      164. Hostname = _Hostname
      165. TimeOut = _TimeOut
      166. End Sub
      167. End Structure
      168. End Class
      169. Friend Class IPPinger
      170. Protected __IP As String
      171. Protected __Scanner As NetworkScanner
      172. Protected __TimeOut As Integer
      173. Public Shared ReadOnly Property StandardTimeOut As Integer
      174. Get
      175. Return 1000
      176. End Get
      177. End Property
      178. Public ReadOnly Property IP As String
      179. Get
      180. Return __IP
      181. End Get
      182. End Property
      183. Public Event GotPingResult(ByVal sender As NetworkScanner, ByVal e As NetworkScanner.PingResult)
      184. Public Sub New(ByVal _Scanner As NetworkScanner, ByVal _IP As String)
      185. __Scanner = _Scanner
      186. __IP = _IP
      187. __TimeOut = 1000
      188. End Sub
      189. Public Sub New(ByVal _Scanner As NetworkScanner, ByVal _IP As String, ByVal _TimeOut As Integer)
      190. __Scanner = _Scanner
      191. __IP = _IP
      192. __TimeOut = _TimeOut
      193. End Sub
      194. Public Sub StartPing()
      195. While __Scanner.CurrentThreads >= __Scanner.MaxThreads : End While
      196. Dim t As New Threading.Thread(AddressOf _ping_ip_thread)
      197. t.Name = __IP & " - Pingthread"
      198. t.Start(__IP)
      199. End Sub
      200. Private Sub _ping_ip_thread(ByVal _IP As Object)
      201. __Scanner.CurrentThreads += 1
      202. Try
      203. Dim Milliseconds As Long = Me.DoPing(_IP.ToString)
      204. Dim result As NetworkScanner.PingResult
      205. If Milliseconds <> -1 Then
      206. Dim HostName As String = Net.Dns.GetHostEntry(_IP.ToString).HostName
      207. result = New NetworkScanner.PingResult(_IP.ToString, True, Milliseconds, HostName, __TimeOut)
      208. Else
      209. result = New NetworkScanner.PingResult(_IP.ToString, False, Milliseconds, String.Empty, __TimeOut)
      210. End If
      211. RaiseEvent GotPingResult(__Scanner, result)
      212. Catch ex As Exception
      213. Throw ex 'Ja, sinnlos, ich weiß. Man könnte auch einen "Nicht-erreichbar"-Pin zurückgeben.
      214. Finally
      215. __Scanner.CurrentThreads -= 1
      216. End Try
      217. End Sub
      218. Private Function DoPing(ByVal _IP As String) As Long
      219. Dim ping As New Net.NetworkInformation.Ping
      220. Dim reply As Net.NetworkInformation.PingReply = ping.Send(_IP, __TimeOut)
      221. If reply.Status = Net.NetworkInformation.IPStatus.Success Then
      222. Return reply.RoundtripTime
      223. Else
      224. Return -1
      225. End If
      226. End Function
      227. End Class




      Für Fragen zu dem Code bin ich gerne offen. Diese können wie gewohnt hier gestellt werden. ;)

      Habt Spaß,
      nikeee
      Von meinem iPhone gesendet

      Dieser Beitrag wurde bereits 12 mal editiert, zuletzt von „nikeee13“ ()

      Ich denke nicht, dass das schwer zu implementieren wäre.
      Ich packs mal schnell rein.

      Edit:
      So, ist drinne.
      Hab Kommandozeilenargumente auch noch gleich mit rein gepackt.
      Von meinem iPhone gesendet

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nikeee13“ ()

      wow super code genau sowas hab ich gesuch ;)

      wie bekomm ich das jetz in ne windows forms anwendung rein?
      das es zb oben ein textfeld ist wo man die ersten 3 stellen der ip eingibt und dann ein button zum ausführen
      und in einem weiteren textfeld die verfühbaren ips angezeigt werden?

      DANKE für eure Hilfe

      lg erbse
      Für eine Windows Forms anwendung musst du ihn umschreiben. da z.B die ganzen WriteLine befehle nicht verwendet werden können, du könntest die Textausgabe ja umleiten, z.B auf ein Label oder eben, wie du sagtest, auf eine TextBox in der dan die fertigen IP's stehen.

      MfG
      Da hier mit mehreren Threads gearbeitet wird, musst du bei der Ausgabe der erreichbaren IPs in z.B: einer Textbox Delegates verwenden, um in den GUI-Thread zu invoken.

      Dort gibt es infos dazu:
      [VB 2010] Threadübergreifend in ListBox schreiben!
      codeproject.com/KB/vb/mutithreading_for_beginer.aspx
      espend.de/artikel/vbnet-thread…ds-invoke-und-events.html

      Ich hab es hier als Konsole hereingestellt, weil der ganze invoke-kram den Code schnell unübersichtlich machen kann. Mir ging es darum, dass man den Code leichter verstehen kann.
      Von meinem iPhone gesendet
      Hallo,

      gibt es einen bestimmten Grund warum du ein Modul gewählt hast und keine Klasse?

      Warum nicht gleich Objektorientiert arbeiten und eine Klasse erstellen, in deren Konstruktor könntest du dann auch direkt die zu scannende IP übergeben und damit die "abc" Variable befüllen (Interessanter Name übrigens...)

      Module sind ein Relikt und sollten nach Möglichkeit nicht mehr verwendet werden.

      Desweiteren könnte man so ganz einfach eine Instanz dieser Klasse in anderen Klassen/Anwendungen benutzen.
      Siehe Polymorphie.
      Ich sehe in deinem Blog nicht ein warum Ich kein Modul verwenden sollte.
      Wenn ich nicht nach OOP programmiere... ist das wirklich so schlimm?
      Und vielleicht hab ich auch was dagegen das meine Module weiterverwendet werden...

      Der Beitrag unter mir enthält einen Gegenbeweis<--- markieren wen es interessiert ^^

      Memo schrieb:

      Ich sehe in deinem Blog nicht ein warum Ich kein Modul verwenden sollte.
      Dann solltest du den Beitrag vielleicht noch ein paar mal durchlesen
      Wenn ich nicht nach OOP programmiere... ist das wirklich so schlimm?
      Ja, denn VB.NET ist eine Objektorientierte Sprache und sollte auch so genutzt werden, wenn du nicht nach OOP programmieren möchtest dann kannst du ja weiterhin VB6 nutzen.
      OOP Hat sehr viele Vorteile, die zb erbse hätte nutzen können, da er dann die Klasse sehr einfach weiter verwenden hätte können.
      Und vielleicht hab ich auch was dagegen das meine Module weiterverwendet werden...
      Wenn du was dagegen hast, dass deine Module, weiter verwendet werden dann solltest du diese nicht im Sourcecode Austausch posten ?(
      Wenn man schon seinen Code postet sollte man schon gucken, dass dieser auch sauber und verständlich ist, damit andere Leute dort durchfinden können, und ganau das bringt OOP mit sich, denn Namen wie "abc" helfen niemandem beim Verstehen.

      bigbasti schrieb:


      denn Namen wie "abc" helfen niemandem beim Verstehen.

      Abc steht für die Bytes der IP. A.B.C.D. (bezogen auf die IP-Abschnitte des Netzwerks)
      Der underscore am Ende der Variable abc_ steht bei meinem Stil immer dafür, dass die Variable von einem Input kommt und noch auf die Gültigkeit geprüft werden muss, bevor man sie in die Variable abc übergibt.
      Wobei ich in meinem Code von einem Netzwerk mit der Subnetmaske 255.255.255.0 ausgehe.

      Ich verwende ein Modul, weil ich einfach alles in eine Konsolenanwendung herein geschrieben habe. Ich kann auch noch eine komplett-OOP-Variante dazu schreiben.
      Von meinem iPhone gesendet

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „nikeee13“ ()

      Hallo Nikeee13,

      der neue Code sieht doch schon um einiges besser aus, ist zwar immer noch ein Modul drin, aber gut ;)

      Ein kleiner Hinweis (optional) könntest du den Code noch weiter verfeinern, indem du ihn komplett unabhängig von der Applikationsform machst, also so, dass man ihn aus einer Forms, Consolen und auch aus einer Webanwendung nuten kann. Momentan ist dein Code immer noch sehr start von der main-Methode abhängig.

      Ein komplett OOP- und unabhängiger Code könnte dann so aufgerufen werden:


      Private Sub Button1_Click()
      Dim scanner As NetworScanner = New NetworkScanner("ipbereich")
      Dim ergebnis As String = scanner.Run() 'oder irgendwas so in der art
      TextBox1.Text = ergebnis
      End Sub


      Mit anderen Worten der Benutzer sollte es später so einfach wie möglich haben :) - damit würdest du Erbse jedenfalls sehr helfen glaube ich ;)

      Du kannst natürlich die Variablen so nennen, wie du es am besten verstehst, ist ja auch völlig normal so, aber wenn man den Code veröffentlicht, will man normalerweise, dass auch andere damit arbeiten.
      Den anderen Menschen kann man das enorm erleichtern, in dem man aussagekräftige Namen verwendet, oder Kommentare in den Code einbaut.
      HI Nikeee,


      offensichtlich hat dich unsere kurze Diskussion angeregt.
      Leider muss ich sagen, mir gefällt dein Code nicht sonderlich.
      Du ermöglichst keine einachen Erweiterungen (zB Pingoptionen, variabler IP Bereich, Rückgabe von Pingzeiten,PC Namen auslesen etc). Du benutzt My.Network.Ping.
      Du implementierst es fest in eine Konsolenanwendung.

      Für einen simplen Massping vll kein schlechter Anfang, aber mehr auch nicht.
      Ich bleibe dabei. Ein vernünftiger Netzwerkscanner ist keine Anfängersache.

      Verbessere deinen Code noch(Siehe Hinweise von Vorrednern), dann kann man damit wirklich was anfangen.
      Ach, und Erläuterungen im Code wären schön..zumindest einige wenige...

      gruss Mono
      Das ist meine Signatur und sie wird wunderbar sein!

      Mono schrieb:

      Für einen simplen Massping vllt. kein schlechter Anfang, aber mehr auch nicht.
      Mehr soll es auch nicht sein.

      Mono schrieb:

      Du implementierst es fest in eine Konsolenanwendung.
      Soll ich es etwa als Classlibrary bereitstellen? Man kann sich ja auch die Klassen in eine Forms-Anwendung packen. Die Verwendung bleibt die gleiche.

      Mono schrieb:

      Ich bleibe dabei. Ein vernünftiger Netzwerkscanner ist keine Anfängersache.
      Ein vernünftiger Scanner kann ebenso ein simpler Scanner sein. Du meinst wahrscheinlich einen umfangreicheren. Naja, ich wollte nur ein Beispiel geben, wie man es mit Multithreading machen könnte. Wer dann noch Sachen wie eine Subnetzmaske haben will, muss sich das selbst implementieren. Mir ging es hier um den Ansatz. (Deshalb auch den Ping aus dem My-Namespace)

      Mono schrieb:

      Verbessere deinen Code noch(Siehe Hinweise von Vorrednern), dann kann man damit wirklich was anfangen.
      Primär geht es nicht um den praktischen Nutzen des Scanners, sondern um die Methode. (siehe einen Quote weiter oben)

      Mono schrieb:

      Ach, und Erläuterungen im Code wären schön..zumindest einige wenige...
      Kann ich machen, schreibe morgen jedoch 4 Stunden lang Mathe, hab gerade besseres zu tun. ^^

      Mono schrieb:

      z.B. Pingoptionen, variabler IP Bereich, Rückgabe von Pingzeiten,PC Namen auslesen etc)
      Lässt sich alles leicht implementieren, da jetzt auch eine OOP-Variante vorliegt. Mal schauen, ob ich noch was dazu mache.

      Edit:
      hab den Code noch mal etwas verbessert/ausgeweitet.
      Von meinem iPhone gesendet

      Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „nikeee13“ ()