Form Eingefroren bei IP adressenabfrage Webclient

  • VB.NET
  • .NET (FX) 4.0

Es gibt 39 Antworten in diesem Thema. Der letzte Beitrag () ist von bigbase.

    Form Eingefroren bei IP adressenabfrage Webclient

    Hi mal wieder ich mit einem neuen Problem

    Vieleicht kann ich irgendwann auch mal helfen xD

    Also ich habe folgendes Problem ich habe im Form Load eine Ip adressen abzeige wenn ich das Programm nun Starte ist die ganze Form so lange eingefroren bis die Ip adresse geladen wurd Wie kann ich das einfreieren vermeiden?

    Code in Form Load

    VB.NET-Quellcode

    1. Dim S As String = GetIP()
    2. Label3.Text = S


    Generierung der IP Abfrage

    VB.NET-Quellcode

    1. Public Shared Function GetIP(Optional ByVal fritzBox As Boolean = False) As String
    2. Dim str As String
    3. If (Not fritzBox) Then
    4. Dim str1 As String = "0.0.0.0"
    5. Try
    6. Dim str2 As String = ""
    7. str2 = (New WebClient()).DownloadString("http://checkip.dyndns.org")
    8. Dim strArrays As String() = str2.Split(New String() {":", "<"}, StringSplitOptions.RemoveEmptyEntries)
    9. str1 = strArrays(6).Trim()
    10. Catch exception As System.Exception
    11. str = str1
    12. Return str
    13. End Try
    14. str = str1
    15. Else
    16. Dim httpWebRequest As System.Net.HttpWebRequest = DirectCast(WebRequest.Create("http://fritz.box:49000/igdupnp/control/WANIPConn1"), System.Net.HttpWebRequest)
    17. Dim length As System.Net.HttpWebRequest = httpWebRequest
    18. length.Method = "POST"
    19. length.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"
    20. length.Headers.Add("SOAPACTION", "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress")
    21. length.ContentType = "text/xml; charset=UTF-8"
    22. length.ContentLength = CLng(297)
    23. length.Timeout = 60000
    24. length.AllowAutoRedirect = True
    25. Dim str3 As String = String.Concat(New String() {"<?xml version=""1.0"" encoding=""utf-8""?>", Environment.NewLine, "<s:Envelope s:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/"" xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">", Environment.NewLine, " <s:Body>", Environment.NewLine, " <u:GetExternalIPAddress xmlns:u=""urn:schemas-upnp-org:service:WANIPConnection:1"" />", Environment.NewLine, " </s:Body>", Environment.NewLine, "</s:Envelope>"})
    26. If (str3.Length <= 0) Then
    27. str = "0.0.0.0"
    28. Else
    29. length.ContentLength = CLng(CInt(Encoding.UTF8.GetBytes(str3).Length))
    30. Dim requestStream As Stream = httpWebRequest.GetRequestStream()
    31. requestStream.Write(Encoding.UTF8.GetBytes(str3), 0, CInt(Encoding.UTF8.GetBytes(str3).Length))
    32. requestStream.Close()
    33. Dim response As HttpWebResponse = DirectCast(length.GetResponse(), HttpWebResponse)
    34. str = Regex.Split(Regex.Split((New StreamReader(response.GetResponseStream())).ReadToEnd(), "<NewExternalIPAddress>")(1), "</NewExternalIPAddress>")(0)
    35. End If
    36. End If
    37. Return str
    38. End Function
    Indem Du aufwendige Arbeiten nicht in den Hauptthread (GUI-Zeichnungsthread) packst, da eben genau dann Dein Programm denkt: "Ui, das ist ganz wichtig! Damit muss ich fertig werden, bevor es weitergeht.", sondern in einen Nebenthread, der entweder beim Programmstart aufgerufen wird oder zu einem gewünschten späteren Zeitpunkt.

    Stichpunkte zur Vollständigkeit
    • ginge auch mit Backgroundworker (veraltet, besser nicht mehr nutzen)
    • oder:

    VB.NET-Quellcode

    1. Dim YourIPAccessThread = New Threading.Thread(AddressOf GetIP)
    2. YourIPAccessThread.IsBackground = True
    3. YourIPAccessThread.Start()

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

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

    VaporiZed schrieb:

    Indem Du aufwendige Arbeiten nicht in den Hauptthread (GUI-Zeichnungsthread) packst, da eben genau dann Dein Programm denkt: "Ui, das ist ganz wichtig! Damit muss ich fertig werden, bevor es weitergeht.", sondern in einen Nebenthread, der entweder beim Programmstart aufgerufen wird oder zu einem gewünschten späteren Zeitpunkt.

    Stichpunkte zur Vollständigkeit
    • ginge auch mit Backgroundworker (veraltet, besser nicht mehr nutzen)
    • oder:

    VB.NET-Quellcode

    1. Dim YourIPAccessThread = New Threading.Thread(AddressOf GetIP)
    2. YourIPAccessThread.IsBackground = True
    3. YourIPAccessThread.Start()




    Sry etwas genauer ich stehe auf dem schlauch
    Arbeite mit Await/Async dann blockiert deine GUI nicht mehr. Ist Ressourcen sparender als ein Thread.

    Das sähe dann so ungefähr aus:


    Private Async Sub FormLoad
    ' ...
    Await Threading.Tasks.Task.Run(AddressOf GetIP)

    '...
    End Sub

    Alles nach dem Aufruf von GetIP wird erst ausgeführt, wenn der Task fertig ist.

    Edit: Brauchst du einen Rückgabewert dürfte das so ungefähr gehen:

    Dim t = Await Threading.Tasks.Task.Run(Function() GetIP)
    t.Result '-> = dein Rückgabewert

    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

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

    Etwas genauer ... puh, schwierig, da ich nicht weiß, an welchem Punkt es jetzt noch hapert. Ich erkläre es nochmal mit anderen Worten. Wenn Du theoretisch 3 Befehle in eine Prozedur schreibst, also z.B. in Deine Form_Load-Sub:

    theoretisches Form_Load-Design

    VB.NET-Quellcode

    1. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. CreateControlItems()
    3. CustomizeControlItems()
    4. LoadAdditionalDataFromFile()
    5. End Sub



    dann arbeitet er eine Funktion/Anweisung nach der anderen ab. Ist er fertig mit der ersten, fängt er erst die zweite an. Ist er damit fertig, fängt er mit der dritten erst an. Und wenn die fertig ausgeführt wurde, ist die Form_Load-Prozedur fertig und die Form wird angezeigt.
    Wenn eine dieser Funktionen (man kann sie auch Aufgaben nennen; auch sämtliche sonstigen Anweisungen betrifft das) sehr lange braucht, wird es auch sehr lange dauern, bis die Form angezeigt wird und der Benutzer könnte meinen, dass sich das Programm aufgehängt hat.
    Erster Schritt zur Lösung: Funktionsgeschwindigkeitflaschenhälse ausfindig machen. Hast Du gemacht. Du wusstest sofort, dass es Deine GetIP-Funktion ist.
    Zweiter Schritt: Flaschenhals durch Veränderung der Funktion versuchen zu beseitigen. Klappt manchmal, aber ich vermute mal, dass Du das schon ohne weitere Erfolge probiert hast und das Ergebnis trotzdem noch nicht schnell genug ist.
    Dritter Schritt: Flaschenhalsfunktion in einem Nebenthread auslagern (Anmerkung für die anderen: Async und Await standen bisher noch nicht auf meiner Agenda || ). Ein Beispiel:

    umgebautes Form_Load-Design

    VB.NET-Quellcode

    1. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. CreateControlItems()
    3. CustomizeControlItems()
    4. Dim BackgroundThread = New Threading.Thread(AddressOf LoadAdditionalDataFromFile)
    5. BackgroundThread.IsBackground = True
    6. BackgroundThread.Start()
    7. End Sub



    Nun werden die ersten beiden Funktionen wie bisher abgearbeitet, die Funktion LoadAdditionalDataFromFile hingegen wird nun in einem Nebenthread aufgerufen, läuft also quasi zeitgleich zum Hauptthread im Hintergrund. Der Hauptthread (bestehend aus Form_Load zuende bringen, Form anzeigen, auf Benutzereingaben reagieren) ist von der Last der zeitaufwendigen Funktion befreit und kann seinen eigentlichen Aufgaben nachgehen. Sobald der Nebenthread fertig ist, also sobald die Funktion LoadAdditionalDataFromFile komplett durchgelaufen ist, ist der Nebenthread beendet.

    Um nun innerhalb des Nebenthreads ein Element aus dem Hauptthread sicher zu ändern, benötigt es einen speziellen Aufruf, da sonst das Programm crasht. Dafür muss am Anfang Deiner Form-Klasse ein Delegat deklariert werden. Der Name ist eigentlich egal, ich nenne ihn mal DelLabelUpdate:
    Delegate Sub DelLabelUpdate(NewLabelText As String)
    In Deinem Nebenthread erfolgt jetzt die Vorbereitung zur Änderung Deines Labels mittels:

    VB.NET-Quellcode

    1. Dim LabelUpdateDelegate As New DelLabelUpdate(AddressOf UpdateLabel)
    2. Invoke(LabelUpdateDelegate, DeinIPStringOderWasImmerImLabelStehenSoll)


    Und noch zusätzlich, um das Label auch zu ändern:

    VB.NET-Quellcode

    1. Private Sub UpdateLabel(NewLabelText As String)
    2. Label1.Text = NewLabelText
    3. End Sub


    ich sehe: mrMo war schneller; @mrMo: Seine GetIP ist eine Funktion. Wenn er den Ergebnis-String/den return-Value weiterverarbeiten will, geht das mit await/async wie?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

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

    VaporiZed schrieb:

    ich sehe: mrMo war schneller

    Bäm :P
    Threading ist hier voll oversized. Nen Thread zu starten kostet Zeit, und wenn in dem Thread nicht permanent irgendwelche Dinge berechne (mit Timer zeug und so kram), verzichte ich aufs Threading und nutze den Task (siehe oben).

    @VaporiZed kennst du dich mit Async und Await aus? Falls nicht schau dir das mal genauer an, dürfte dir gefallen. Hab mich damit einige Tage beschäftigt und finds echt komfortabel :)

    Edit: Braucht man einen Rückgabewert dürfte das so ungefähr gehen:

    Dim t = Await Threading.Tasks.Task.Run(Function() GetIP)
    t.Result '-> = dein Rückgabewert
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Ich seh grad, dass t dann schon vom GetIP-ReturnValue-Typ ist. also schon ein string. Wieder was dazugelernt. Man muss sich nur mal damit beschäftigen :rolleyes:
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Wieder was dazugelernt. Man muss sich nur mal damit beschäftigen :rolleyes:


    Freut mich :)

    Du kannst auch mehrere Tasks Starten (Ohne Await) und dann folgendes tun:

    Dim t1 = Threading.Tasks.Task.Run(Function() Foo1)
    Dim t2 = Threading.Tasks.Task.Run(Function() Foo2)
    Dim t3 = Threading.Tasks.Task.Run(Function() Foo3)
    Await(t1,t2, t3)

    Die 3 Methoden werden ausgeführt und es geht beim Await erst weiter, wenn die 3 Ergebnisse da sind. Auch hier blockiert die GUI nicht.

    Übrigens, Invoken kostet Zeit, daher sollte das nur im Notfall gemacht werden. Im schlimmsten Fall, frisst das Invoken die durch den Thread/Task gewonnene Zeit wieder auf und die GUI blockiert wieder.

    Idealfall:
    - Daten Async laden (keine GUI Zugriffe)
    - Wenn du alle Daten zusammen hast, die Daten verarbeiten und die GUI damit aktualisieren
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    mrMo schrieb:

    Arbeite mit Await/Async dann blockiert deine GUI nicht mehr. Ist Ressourcen sparender als ein Thread.

    Das sähe dann so ungefähr aus:


    Private Async Sub FormLoad
    ' ...
    Await Threading.Tasks.Task.Run(AddressOf GetIP)

    '...
    End Sub

    Alles nach dem Aufruf von GetIP wird erst ausgeführt, wenn der Task fertig ist.

    Edit: Brauchst du einen Rückgabewert dürfte das so ungefähr gehen:

    Dim t = Await Threading.Tasks.Task.Run(Function() GetIP)
    t.Result '-> = dein Rückgabewert



    Bin damit leider immer noch leicht überfordert wie gesagt bin ein blutiger anfänger
    Ich habe das ganze mal gegoogelt und mir einige videos angeschaut aber aktuell arbeite ich mit .net4.0 und das fängt alles erst 4,5 an



    Habe das nun so versucht aber das will auch nicht :(

    VB.NET-Quellcode

    1. Public Shared Function GetIP(Optional ByVal fritzBox As Boolean = False) As String
    2. Dim str As String
    3. If (Not fritzBox) Then
    4. Dim str1 As String = "0.0.0.0"
    5. Try
    6. Dim str2 As String = ""
    7. str2 = (New WebClient()).DownloadStringAsync(New Uri("http://checkip.dyndns.org"))
    8. Dim strArrays As String() = str2.Split(New String() {":", "<"}, StringSplitOptions.RemoveEmptyEntries)
    9. str1 = strArrays(6).Trim()
    10. Catch exception As System.Exception
    11. str = str1
    12. Return str
    13. End Try

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

    Läuft es denn so wie es soll, wenn du es nicht async machst?
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    mrMo schrieb:

    Läuft es denn so wie es soll, wenn du es nicht async machst?



    Diese Funktion Läuft Problemlos aber bis die adresse in Label 3 angezeigt werden kann hängt die form

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Shared Function GetIP(Optional ByVal fritzBox As Boolean = False) As String
    2. Dim str As String
    3. If (Not fritzBox) Then
    4. Dim str1 As String = "0.0.0.0"
    5. Try
    6. Dim str2 As String = ""
    7. str2 = (New WebClient()).DownloadString("http://checkip.dyndns.org")
    8. Dim strArrays As String() = str2.Split(New String() {":", "<"}, StringSplitOptions.RemoveEmptyEntries)
    9. str1 = strArrays(6).Trim()
    10. Catch exception As System.Exception
    11. str = str1
    12. Return str
    13. End Try
    14. str = str1
    15. Else
    16. Dim httpWebRequest As System.Net.HttpWebRequest = DirectCast(WebRequest.Create("http://fritz.box:49000/igdupnp/control/WANIPConn1"), System.Net.HttpWebRequest)
    17. Dim length As System.Net.HttpWebRequest = httpWebRequest
    18. length.Method = "POST"
    19. length.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"
    20. length.Headers.Add("SOAPACTION", "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress")
    21. length.ContentType = "text/xml; charset=UTF-8"
    22. length.ContentLength = CLng(297)
    23. length.Timeout = 60000
    24. length.AllowAutoRedirect = True
    25. Dim str3 As String = String.Concat(New String() {"<?xml version=""1.0"" encoding=""utf-8""?>", Environment.NewLine, "<s:Envelope s:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/"" xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">", Environment.NewLine, " <s:Body>", Environment.NewLine, " <u:GetExternalIPAddress xmlns:u=""urn:schemas-upnp-org:service:WANIPConnection:1"" />", Environment.NewLine, " </s:Body>", Environment.NewLine, "</s:Envelope>"})
    26. If (str3.Length <= 0) Then
    27. str = "0.0.0.0"
    28. Else
    29. length.ContentLength = CLng(CInt(Encoding.UTF8.GetBytes(str3).Length))
    30. Dim requestStream As Stream = httpWebRequest.GetRequestStream()
    31. requestStream.Write(Encoding.UTF8.GetBytes(str3), 0, CInt(Encoding.UTF8.GetBytes(str3).Length))
    32. requestStream.Close()
    33. Dim response As HttpWebResponse = DirectCast(length.GetResponse(), HttpWebResponse)
    34. str = Regex.Split(Regex.Split((New StreamReader(response.GetResponseStream())).ReadToEnd(), "<NewExternalIPAddress>")(1), "</NewExternalIPAddress>")(0)
    35. End If
    36. End If
    37. Return str
    38. End Function
    Schreib im form load Async rein
    -> Private Async Sub (...)

    Dann rufst du im FormLoad deine Methode so auf:

    Dim S = System.Threading.Tasks.Task.Run(Function() GetIP())
    Await S
    Label3.Text = S
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    mrMo schrieb:

    Schreib im form load Async rein
    -> Private Async Sub (...)

    Dann rufst du im FormLoad deine Methode so auf:

    Dim S = System.Threading.Tasks.Task.Run(Function() GetIP())
    Await S
    Label3.Text = S


    Edit mein Aktueller Form Load

    VB.NET-Quellcode

    1. ​Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    2. Label5.Visible = False
    3. TextBox15.Visible = True
    4. Me.FormBorderStyle = Windows.Forms.FormBorderStyle.FixedSingle
    5. MaximizeBox = False
    6. MinimizeBox = False
    7. Dim S As String = GetIP()
    8. Label3.Text = S
    9. 'Laden der Einstellungen in Settings Tab
    10. 'CheckBox1.CheckState = My.Settings.Settings
    11. 'CheckBox2.CheckState = My.Settings.Settings
    12. 'CheckBox3.CheckState = My.Settings.Settings
    13. End Sub

    Fehler 3 "Await" wurde nicht deklariert. Auf das Objekt kann aufgrund seiner Schutzstufe möglicherweise nicht zugegriffen werden. C:\Users\User\Documents\Visual Studio 2010\Projects\WindowsApplication1\WindowsApplication1\Form1.vb 253 9 WindowsApplication1

    Fehler 1 "end of"-Anweisung erwartet. C:\Users\User\Documents\Visual Studio 2010\Projects\WindowsApplication1\WindowsApplication1\Form1.vb 251 23 WindowsApplication1

    Fehler 2 "Run" ist kein Member von "System.Threading.Tasks.Task". C:\Users\User\Documents\Visual Studio 2010\Projects\WindowsApplication1\WindowsApplication1\Form1.vb 252 17 WindowsApplication1
    Stell mal auf .Net Framework 4.5 um. Im 4er scheint es das noch nicht zu geben.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Dann wird das nix mit dem Task. Warum arbeitest du mit so ner alten Version? Lad dir doch die aktuelle Visual Studio Community Edition runter. Die gibts für umme.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    mrMo schrieb:

    Dann wird das nix mit dem Task. Warum arbeitest du mit so ner alten Version? Lad dir doch die aktuelle Visual Studio Community Edition runter. Die gibts für umme.


    Irgendwann mal

    Da ich hier keine Lösung finde muss ich wohl das ganze erstmal aus dem form load nehmen und mit einem button umsetzen

    Schade
    Und mit der Threading Lösung von @VaporiZed klappts nicht?
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen