StackOwerFlow Exception

  • VB.NET

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von Patrick1993.

    StackOwerFlow Exception

    Hallo Leute,
    Ich habe vor geraumer Zeit mit TCP Angefangen.
    Soweit sogut, nun habe ich ein Programm von mit auf TCP umgebaut das auch läuft.
    Jedoch bekomme ich alle X Stunden/Tage eine StackOwerflow Exception.

    Woran kann das liegen ??

    Der Code des Servers:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Net, System.IO, System.Net.Sockets, System.Text
    2. Module Module1
    3. Private cli As New TcpClient
    4. Private srv As TcpListener
    5. Private ip As IPEndPoint = New IPEndPoint(IPAddress.Any, 8000)
    6. Private list_leit As New List(Of Verb)
    7. Private list_dme As New List(Of Verb)
    8. Private list_fms As New List(Of Verb)
    9. Private einsatz As Integer
    10. Dim p As String
    11. Private Structure Verb
    12. Dim stream As NetworkStream
    13. Dim kennung As String
    14. Dim streamr As StreamReader
    15. Dim streamw As StreamWriter
    16. End Structure
    17. Sub Main()
    18. p = "config.ini"
    19. srv = New TcpListener(ip)
    20. srv.Start()
    21. Console.WriteLine("Server ist gestartet...")
    22. If File.Exists(p) Then einsatz = CInt(IO.File.ReadAllText(p)) Else einsatz = 1
    23. Dim a As String = CStr(einsatz)
    24. Console.WriteLine("Einsatznummer: " & a)
    25. Dim s As New Threading.Thread(AddressOf speichern)
    26. s.IsBackground = True
    27. s.Start()
    28. While True
    29. cli = srv.AcceptTcpClient
    30. Dim con As New Verb
    31. con.stream = cli.GetStream
    32. con.streamr = New StreamReader(con.stream)
    33. con.streamw = New StreamWriter(con.stream)
    34. con.kennung = con.streamr.ReadLine
    35. If con.kennung = "leit" Then
    36. Console.WriteLine("Leitstelle hat sich verbunden")
    37. list_leit.Add(con)
    38. con.streamw.WriteLine("Einsatz:" & CStr(einsatz))
    39. con.streamw.Flush()
    40. verbunden()
    41. Dim t As New System.Threading.Thread(AddressOf listen_leit)
    42. t.Start(con)
    43. End If
    44. If con.kennung = "dme" Then
    45. Console.WriteLine("DME hat sich verbunden")
    46. list_dme.Add(con)
    47. verbunden()
    48. Dim t As New System.Threading.Thread(AddressOf listen_dme)
    49. t.Start(con)
    50. End If
    51. If con.kennung = "FMS" Then
    52. Console.WriteLine("FMS hat sich verbunden")
    53. list_fms.Add(con)
    54. verbunden()
    55. Dim t As New Threading.Thread(AddressOf listen_fms)
    56. t.Start(con)
    57. End If
    58. End While
    59. End Sub
    60. Private Sub verbunden()
    61. Dim leit As Integer = list_leit.Count
    62. Dim dme As Integer = list_dme.Count
    63. Dim fms As Integer = list_fms.Count
    64. Console.WriteLine("------------------------------------------------")
    65. Console.WriteLine("Online Leistelle: {0}", leit)
    66. Console.WriteLine("Online DME: {0}", dme)
    67. Console.WriteLine("Online FMS: {0}", fms)
    68. Console.WriteLine("Aktuelle Einsatznummer: {0}", einsatz)
    69. Console.WriteLine("------------------------------------------------")
    70. End Sub
    71. Private Sub speichern()
    72. Dim e As String = CStr(einsatz)
    73. IO.File.WriteAllText(p, e)
    74. Threading.Thread.Sleep(2500)
    75. speichern()
    76. End Sub
    77. Private Sub listen_leit(ByVal con As Object)
    78. Dim c As Verb = CType(con, Verb)
    79. Do
    80. Try
    81. Dim tmp As String = c.streamr.ReadLine
    82. If tmp.StartsWith("#Einsatz") Then
    83. senden(tmp.Replace("#Einsatz", Nothing), "leit")
    84. einsatz = einsatz + 1
    85. c.streamw.WriteLine("Einsatz:" & CStr(einsatz))
    86. c.streamw.Flush()
    87. Console.WriteLine("Einsatz wurde gesendet...")
    88. Console.WriteLine("Aktuelle Einsatznummer: {0}", einsatz)
    89. End If
    90. Catch ex As Exception
    91. list_leit.Remove(c)
    92. Console.WriteLine("Leistelle hat die Verbindungen geschlossen")
    93. verbunden()
    94. Exit Do
    95. End Try
    96. Loop
    97. End Sub
    98. Private Sub listen_dme(ByVal con As Object)
    99. Dim c As Verb = CType(con, Verb)
    100. Do
    101. Try
    102. Dim tmp As String = c.streamr.ReadLine
    103. Catch ex As Exception
    104. list_dme.Remove(c)
    105. Console.WriteLine("DME hat die Verbindungen geschlossen")
    106. verbunden()
    107. Exit Do
    108. End Try
    109. Loop
    110. End Sub
    111. Private Sub listen_fms(ByVal con As Object)
    112. Dim c As Verb = CType(con, Verb)
    113. Do
    114. Try
    115. Dim tmp As String = c.streamr.ReadLine
    116. senden(tmp, "fms")
    117. Catch ex As Exception
    118. list_fms.Remove(c)
    119. Console.WriteLine("FMS hat die Verbindung geschlossen")
    120. verbunden()
    121. Exit Do
    122. End Try
    123. Loop
    124. End Sub
    125. Private Sub senden(ByVal mes As String, ByVal ken As String)
    126. If ken = "leit" Then
    127. For Each c As Verb In list_dme
    128. c.streamw.WriteLine(mes)
    129. c.streamw.Flush()
    130. Next
    131. End If
    132. If ken = "fms" Then
    133. For Each c As Verb In list_leit
    134. c.streamw.WriteLine(mes)
    135. c.streamw.Flush()
    136. Next
    137. End If
    138. End Sub
    139. End Module


    Die Fehlermeldung ist im Anhang
    Hoffe ihr könnt mir auf die Sprünge helfen
    Bilder
    • Unbenannt-1.jpg

      251,59 kB, 897×645, 182 mal angesehen

    Wenn zu viele Verbindungen gleichzeitig aktiv sind, dann laufen in deinem Programm zu viele Threads. Die fressen richtig viel Speicher auf dem Stack, und in Verbindung mit den ganzen Netztwerkegeschichten, die auch nicht ganz ohne sind, kommt es dann irgendwann zu einem Überlauf.
    kann man den überlauf irgendwie verhindern ?

    Du könntest versuchen anstatt für jede Verbindung nen extra Thread zu erstellen irgenwie mit dem Threadpool oder Async-Methoden zu arbeiten. Da ich aber sowas in der Art noch nicht gemacht habe kann ich dir dazu leider nichts genaues zu sagen.

    Patrick1993 schrieb:

    VB.NET-Quellcode

    1. Private Sub speichern()
    2. Dim e As String = CStr(einsatz)
    3. IO.File.WriteAllText(p, e)
    4. Threading.Thread.Sleep(2500) ' Erklärt die lange Dauer bis zum Stack Overflow....
    5. speichern() 'Rekursion ohne Abbruchbedingung
    6. End Sub

    ich vermute mal der fehler liegt hier !
    @Artentus:
    Async kann ich leider nich verwenden da ich mit VB 2010 Arbeite. Threadpool müsste ich mich mal schlau machen wie das gehen soll

    @Quadsoft:
    Denkst du das der Thread zulange "schläft" und es dadurch zuviel wird ?

    ne du hast da ne rekursion drin ... hat quad aber schon erwähnt 'Rekursion ohne Abbruchbedingung

    Quellcode

    1. speichern()
    2. speichern()
    3. speichern()
    4. speichern()
    5. speichern()
    6. speichern()
    7. speichern()
    8. ...
    9. speichern()
    und irgendwann erreichst du halt den punkt an dem der StackOverFlow auftritt - dein sleep verzögert das ganze nur
    Also müsste ich das ganze im grund irgendwie Abbrechen wenn ich es richtig verstehe

    Patrick1993 schrieb:

    Denkst du das der Thread zulange "schläft" und es dadurch zuviel wird ?

    Bei einem Funktionsaufruf wird die Rücksprungadresse auf den Stack gepusht (und dann nach dem Sprung wieder gepoppt). Wenn eine Rekursion zu weit läuft, läuft der Stapel über, da der Stack nicht mehr "geleert" wird. Das endet dann in einem klassichen Stackoverlfow.
    Ich musste auch mal schlau klingen. :P

    @Quadsoft: Hat also recht. Der Fehler wird dort liegen.

    Patrick1993 schrieb:

    Also müsste ich das ganze im grund irgendwie Abbrechen wenn ich es richtig verstehe
    Natürlich, sonst würdest du den Thread auch ewig blockieren. Es kann also gar nicht in deinem Sinne sein, es so zu machen.
    Von meinem iPhone gesendet
    @mikee13
    Wir könnte man eine solche Rekursion Blockieren ?

    @Artentus
    Ich tu dort die Nummer aus einer Textdatei auslesen bzw die neuste (die gesendet wurde) speichern damit man die nicht immer selbst errechnen muss.
    Wir würde eine solche sache in einer Schleife aussehen da stehe ich aufm Schlauch

    Die sinnvolle bedinung were z.b Console.ReadLine() oder sehe ich da was falsch

    Also würde das ganze mehr oder weniger aussehen wie:

    VB.NET-Quellcode

    1. Do
    2. Try
    3. 'Hier dann das Speicherzeugs rein
    4. Catch ex As ThreadAbortException
    5. Console.Writeline(ex.Message)
    6. End Try
    7. End Do


    Ich glaube ich bin auf dem richtigen Wege oder ?

    Also im Grunde so:

    VB.NET-Quellcode

    1. Private Sub speichern()
    2. Try
    3. While True
    4. Dim e As String = CStr(einsatz)
    5. IO.File.WriteAllText(p, e)
    6. Threading.Thread.Sleep(2500)
    7. speichern()
    8. End While
    9. Catch ex As Threading.ThreadAbortException
    10. Console.WriteLine(ex.Message)
    11. End Try
    12. End Sub


    ok habs mir mal umgeschrieben direkt mal testen :)