vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
NEU! sevCoolbar 3.0 - Professionelle Toolbars im modernen Design!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück

 Sie sind aktuell nicht angemeldet.Funktionen: Einloggen  |  Neu registrieren  |  Suchen

VB.NET - Ein- und Umsteiger
Thread per Button sicher schließen 
Autor: Wavemark
Datum: 02.07.12 12:45

Hallo,

ich habe momentan ein Problem mit dem ich nicht so recht weiterkomme.

Ein kleiner TCP-Server der logischerweise in einem Thread laufen muss.
Nun möchte ich diesen Thread mit einem Button sowohl starten als auch schließen
um beispielsweise den Port ändern zu können.

Problem ist das Schließen des Threads. Es gibt viele Code-Samples, allerdings
wird dort nur gestartet und das ist eben nicht mein Problem.

ABORT funktioniert nicht da damit der Thread lediglich angehalten wird.

Vielleicht kann mir da jemand helfen.

Vielen Dank im voraus
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Preisser
Datum: 02.07.12 14:49

Hallo,

mit Thread.Abort() wird eine ThreadAbortException ausgelöst, was meist (falls nicht gerade unmanaged Code ausgeführt wird) zum sofortigen Abbruch des Threads führt (also ein hartes/abruptes Ende, allerdings wird z.B. Code in Finally-Blöcken noch ausgeführt).

Wenn der Thread allerdings beispielsweise durch blockierende Methoden häufig im WaitSleepJoin-Zustand befindet, ist es besser, den Thread zu interrupten, wodurch eine ThreadInterruptedException ausgelöst wird, sobald der Thread das nächste Mal in den WaitSleepJoin-Zustand wechselt (dadurch ist es besser vorhersehbar, wo die Exception auftreten wird).

Anscheinend befindet sich ein Thread jedoch beim Aufruf von TcpListener.AcceptTcpClient() bzw. .AcceptSocket() nicht im WaitSleepJoin-, sondern im Running-Zustand (wohl wegen des Aufrufs von blockierenden Win-APIs, also unmanaged Code), wodurch die Methode mit .Interrupt() nicht funktioniert. Man kann aber die Stop()-Methode des TcpListeners aufrufen, wodurch dieser auch mit dem Abhören aufhört und in .AcceptTcpClient() eine SocketException geworfen wird.

Beitrag wurde zuletzt am 02.07.12 um 15:09:46 editiert.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Wavemark
Datum: 02.07.12 16:40

Es ist genauso, wie im 3.Absatz geschildert, TcpListener.AcceptTcpClient().

Nur, auch TcpListener.Stop() ändert nichts an der Situation. Ist bereits eingebaut. Der Thread lässt sich schließen, aber AcceptTcpClient() läuft weiter. Auch nach Application.Exit.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Manfred X
Datum: 02.07.12 16:44

Hallo!

Listen!
Stop <> Close
http://msdn.microsoft.com/de-de/library/wahsac9k.aspx

Du mußt vermutlich noch offene Verbindungen schließen.

MfG
Manfred

Beitrag wurde zuletzt am 02.07.12 um 16:53:20 editiert.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Preisser
Datum: 02.07.12 16:55

Hallo,

bei mir führt der Aufruf von TcpListener.Stop() dazu, dass TcpListener.AcceptTcpClient() im anderen Thread unmittelbar danach eine SocketException mit der Message "Ein Blockierungsvorgang wurde durch einen Aufruf von WSACancelBlockingCall unterbrochen" wirft und somit der Thread beendet werden kann. Evtl. noch offene TCP-Verbindungen (TcpClients) bleiben dabei bestehen.

Ich habe dazu mal folgenden Code verwendet:
    Private tcpListenerThread As Thread
    Private tcpListener As TcpListener
 
 
    Private Sub StartTcpListener()
        tcpListener = New TcpListener(IPAddress.Any, 12345)
        tcpListener.Start()
        tcpListenerThread = New Thread( _
            Sub()
                RunTcpListenerThreadThread(tcpListener)
            End Sub)
        tcpListenerThread.Start()
 
    End Sub
 
    Private Sub RunTcpListenerThreadThread(listener As TcpListener)
        Try
            Do While True
                Dim tcp As TcpClient = listener.AcceptTcpClient()
                Debug.WriteLine("Accepted")
                ' den tcp-client verarbeiten....
                'tcp.Close()
            Loop
        Catch ex As SocketException
            'Vermutlich wurde .Stop aufgerufen
            Debug.WriteLine(ex.ToString())
        End Try
    End Sub
 
    Private Sub StopTcpListener()
        tcpListener.Stop() 'Listening beenden
        tcpListenerThread.Join() 'Auf Threadende warten
    End Sub
Dann kann beispielsweise ein Button StartTcpListener() aufrufen, womit der TcpListener gestartet wird und auf eingehende Verbindungen wartet. Ein anderer Button kann später StopTcpListener() aufrufen, womit der TcpListener beendet wird.

Beitrag wurde zuletzt am 02.07.12 um 16:58:32 editiert.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Wavemark
Datum: 02.07.12 18:04

Bei mir kommt genau die gleiche Exception Nach STOP. Ich denke, es liegt gar nicht am Thread. der ist schon geschlossen. Wenn ich mit VS unterbreche, hängt er an dieser Zeile fest:

client = server.AcceptTcpClient

Es besteht keine Verbindung und es liegt auch keine an.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Preisser
Datum: 02.07.12 18:08

Hallo,

ich fürchte ich verstehe dich nicht ganz. Wenn man Stop() aufruft, müsste die Methode AcceptTcpClient() ja die SocketException werfen, die man dann auffangen kann und wodurch sich der Thread beenden kann.

Wie genau sieht denn dein Code für den separaten Thread aus?

Beitrag wurde zuletzt am 02.07.12 um 18:11:42 editiert.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Wavemark
Datum: 02.07.12 18:36

Das ist der Thread. Es gibt noch einen Zweiten am Ende (th), aber der wird nur bei Verbindung gestartet.

Sub ServerStart()
        Log("Server START")
        server = New TcpListener(ipendpoint)
        server.Start()
 
        While True ' wir warten auf eine neue verbindung...
            Try
                Try
                    client = server.AcceptTcpClient   '<----- hier bleibt er 
                    ' hängen
                Catch ex As Exception                 '       auch nach 
                ' Application:Exit
 
 
                    MsgBox(ex.Message)
 
                End Try
 
                Dim c As New Connection
                c.stream = client.GetStream
                c.streamr = New StreamReader(c.stream)
                c.streamw = New StreamWriter(c.stream)
                Dim data() As String = (c.streamr.ReadLine).Split(Chr(126))
                c.cmd = data(0)
                c.nick = data(1)     
                c.pass = data(2)
                list.Add(c)
                Log(c.nick + " LogIn") 
 
                th.Start(c)
            Catch ex As Exception
                Log("Server STOP")
                Exit While
            End Try
        End While
    End Sub
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Preisser
Datum: 02.07.12 19:06

Hallo,

der innere Try-Catch-Block führt dazu, dass zwar die SocketException aufgefangen wird, die bei .AcceptTcpClient() auftreten kann, danach wird die Methode aber weiter ausgeführt und es könnten andere, unerwartete Exceptions auftreten (evtl. noch ein Exit While im Catch-BLock hinzufügen, oder z.B. einen Try-Catch-Block außerhalb der Schleife verwenden)

Soweit ich sehe, liest du bei einer eingehenden Verbindung auch im gleichen Thread schon etwas, bevor ein weiterer Thread für diesen TcpClient gestartet wird - dadurch kann es allerdings passieren, dass sich der Thread nicht beendet bzw. vorübergehend keine weiteren, in der Zwischenzeit eingehenden, TCP-Verbindungen annimmt, wenn der TcpListener gerade einen neuen TcpClient angenommen hat und dort die blockierende Read-Methode aufruft, der Client jedoch nichts sendet. Ich würde alle Lesevorgänge in dem neuen Thread durchführen.

(Da du den TcpListener erst im neuen Thread erstellst, könnte es passieren, dass dessen Referenz noch gar nicht im Feld (Objektvariable) "server" abgelegt wurde, wenn der andere (GUI-)Thread dessen Stop()-Methode aufrufen will - sollte aber mit dem aktuellen Problem nichts zu tun haben.)

Du schriebst im vorherigen Beitrag "Bei mir kommt genau die gleiche Exception Nach STOP".
In welcher Zeile tritt die Exception auf?

Beitrag wurde zuletzt am 02.07.12 um 19:18:35 editiert.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Wavemark
Datum: 02.07.12 19:39

Diese Exception tritt nach Server.Stop im TryCatch Block für 'client = server.AcceptTcpClient' auf.

Das ist ja auch so ok, denk ich mal. Merkwürdig ist nur, dass AcceptTcpClient dadurch nicht beendet wird. Ich hab's hundert mal probiert. Ob ich nun per Button den Thread und Server abschalte oder ich mit Application.Exit die Anwendung schließe, AcceptTcpClient wird nicht verlassen. Ich verzweifle hier schon.

Was das Lesen im ersten Thread betrifft, ist das schon richtig. Dieses Programm ist auch nur ein Test und funktioniert mit einem Client wunderbar. Ich werde sicher noch Änderungen vornehmen. Mir ging es nur erst mal um die Funktion.

Übrigens vielen Dank, dass du dir soviel Zeit dafür nimmst
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Wavemark
Datum: 03.07.12 01:34

Ich hab das Problemchen gelöst. Oft sieht man wirklich den Wald vor Bäumen nicht.
Try
 
     client = server.AcceptTcpClient
 
Catch ex As Exception
 
     If ServerThread.ThreadState=ThreadState.Stopped Then
	Log("Server STOP")
	Exit While
     End If
 
End Try
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Samael
Datum: 05.07.12 20:48

Und Deine Lösung ist eine unschöne Lösung. Hier die korrekte Lösung des Problems.

Du legst Dir ein Flag an, z. B. serverRunning. Bevor der Server gestartet wird:

z. B. so:

serverRunning = true
 
do
 if not serverRunning then exit do
 
 client = server.AcceptCilent()
loop
So, klickst Du nun auf Stop, dann setzt Du das Flag auf false und verbindest Dich selbst auf Deinen Server, verstehst Du? Dein "temporärer" Client wird akzeptiert und bevor die .Accept-Funktion wieder aufgerufen wird der Thread beendet. Saubere Lösung, ohne Exeption und Try-Catch..

o/
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Thread per Button sicher schließen 
Autor: Preisser
Datum: 05.07.12 23:09

Hallo,

diese Art des Thread-Beendens benutzt man, wenn der Thread dauerhaft etwas ausführt (z.B. Endlosschleife), um ihn auf saubere Weise zu beenden (bei Thread.Abort() kann man nicht vorhersehen, wo der Thread abgebrochen werden wird).

Wenn man aber blockierende Methoden benutzt, geht das nicht, weil der Thread ja auf eine Nachricht eines anderen Threads wartet - in dem Fall kann man Thread.Interrupt() benutzen, wodurch eine ThreadInterruptedException ausgelöst wird, wenn der Thread das nächste Mal im WaitSleepJoin-Zustand ist.

Da allerdings der Thread beim Aufruf von TcpServer.AcceptTcpClient() weiterhin im Running-Zustand ist (durch den Aufruf von blockierenden WinAPIs), geht dies auch nicht - man muss deshalb die Close()-Methode des TcpListeners aufrufen, damit in der blockierenden .AcceptTcpClient()-Methode eine SocketException geworfen wird und diese somit zurückkehrt.

Bei deinem Beispiel müsste sich zuerst ein weiterer Client zum Server verbinden, damit die Methode AcceptTcpClient() zurückkehrt und den Zustand des Flags prüfen kann - daher kann man hiervon nicht unbedingt als saubere Lösung sprechen.

In meinem vorherigen Beitrag hatte ich einen Beispielcode mit dem Aufruf der Close-Methode angegeben. Der Try-Catch-Block ist notwendig, denn irgendwie muss die AcceptTcpClient()-Methode ja mitteilen können, dass kein neuer Client angelegt wurde, sondern der TcpListener beendet wurde.

Beitrag wurde zuletzt am 05.07.12 um 23:37:08 editiert.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Sie sind nicht angemeldet!
Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.

Einloggen  |  Neu registrieren

Funktionen:  Zum Thema  |  GesamtübersichtSuchen 

nach obenzurück
 
   

Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel