Tcplistener funktioniert 1x

  • VB.NET
  • .NET (FX) 4.0

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von Vainamo.

    Tcplistener funktioniert 1x

    Hallo zusammen,

    ich habe das Tcplistener Beispiel hier aus dem Forum versucht auf eine GUI Anwendung umzuschreiben. Das funktioniert auch, aber nur 1x. Danach muss ich die Anwendung schließen und wieder starten. Hier mein Code:

    VB.NET-Quellcode

    1. Imports System.Net.Sockets
    2. Imports System.IO
    3. Imports System.Net
    4. Public Class Form1
    5. Private server As TcpListener
    6. Private client As New TcpClient
    7. Private ipendpoint As IPEndPoint = New IPEndPoint(IPAddress.Any, 8000) ' eingestellt ist port 8000. dieser muss ggf. freigegeben sein!
    8. Private list As New List(Of Connection)
    9. Private Structure Connection
    10. Dim stream As NetworkStream
    11. Dim streamw As StreamWriter
    12. Dim streamr As StreamReader
    13. End Structure
    14. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    15. server = New TcpListener(ipendpoint)
    16. server.Start()
    17. Dim t As New Threading.Thread(AddressOf ListenToConnection)
    18. t.Start()
    19. End Sub
    20. Private Sub ListenToConnection(ByVal con As Connection)
    21. While True ' wir warten auf eine neue verbindung...
    22. Try
    23. client = server.AcceptTcpClient
    24. Dim c As New Connection ' und erstellen für die neue verbindung eine neue connection...
    25. c.stream = client.GetStream
    26. c.streamr = New StreamReader(c.stream)
    27. c.streamw = New StreamWriter(c.stream)
    28. Dim temp As String = c.streamr.ReadLine
    29. Me.Invoke(Sub() Me.TextBox1.Text = temp)
    30. Catch ex As Exception
    31. MessageBox.Show(ex.ToString)
    32. End Try
    33. End While
    34. End Sub
    35. End Class


    Ich stehe hier gerade auf dem Schlauch, da ich nicht weis warum der Thread nur 1x durchlaufen wird nach dem die Connection aufgebaut wurde. Kann mir jemand einen Tip geben ?

    Danke im Voraus
    Gruß Kay
    Dein TcpListener darf nur einmal zu Programmstart mit new initialisiert und mit .Start gestartet werden. Deine Arbeiten in Button1_Click gehören somit in Form1_Load.
    Das führt dazu, dass der Server/Listener während des ganzen Programmablaufs aktiv bleibt und quasi immer darauf wartet, dass jemand bei ihm anruft/zu ihm spricht (z.B. wie beim Notruf).
    Es ginge auch, dass man den TcpListener zeitweise quasi abschaltet, indem der Nebenthread tatsächlich nur bei Button1_Click gestartet wird, aber das wär, als ob man beim Notruf anruft und darauf hoffen muss, dass da jemand in der Rettungsleitstelle sitzt und nicht grad in der Pause ist.

    EDIT: Du versuchst grad, mehrere Notrufstellen über die selbe Telefonnummer der Bevölkerung zur Verfügung zu stellen (mehrere TcpListener zu erzeugen, alle mit den selben Verbindungsdaten), je eine neue pro ButtonClick. Das geht schief. Fliegt da keine Exception?
    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 2 mal editiert, zuletzt von „VaporiZed“ ()

    Vollzitat entfernt. ~Trade

    @Bluespide
    Der Client schickt ja einen String. Ich bekomme den auch im Textfeld angezeigt. Schickt der Client jetzt einen anderen String wird der nicht empfangen. Schließe ich das Programm und Starte es wieder funktioniert es wieder 1x.

    Vollzitat entfernt. ~Trade

    @VaporiZed
    Da komme ich grad nicht mit :)

    Mit dem Button erzeuge ich einen Tcplistener der doch egal ob er über den Button erzeugt wird oder über die FormLoad Methode nur 1x erzeugt wird. Nach dem der Tcplistener erstellt wurde wird ein neuer Thread mit dem Verweis auf den Tcplistener erstellt. Korrigiere mich bitte wenn ich falsch liege, aber sollte der Thread dann nicht so lange laufen bis er beendet wird ? Eine Exception bekomme ich nämlich nicht.

    Gruß Kay

    Bitte keine Crossposts. Du kannst Deinen vorherigen Beitrag editieren. => Beiträge zusammengefügt. ~Trade

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

    @kayle
    Dein Server kann nur eine Nachricht empfangen.
    Die erste Nachricht wird hier Tcplistener funktioniert 1x noch ausgegeben.
    Danach läuft die Schleife weiter und der Server wartet auf die nächste Verbindung. Deine bestehende Verbindung wird dann weder weiter beachtet, noch fallengelassen.
    Wenn du also weitere Clients verbinden würdest, könnten die auch jeweils eine Nachricht senden und dann ist schluß.
    Du musst stattdessen die Connection an eine weitere Methode in einem neuen Thread übergeben. Zum Beispiel so:

    C#-Quellcode

    1. // Die folgenden Zwei Zeilen gehören in die ListenToConnection Sub bei Zeile 40.
    2. var ListeningThread = new Thread(Listen);
    3. ListeningThread.Start(c);
    4. // Diese Methode übernimmt das Verarbeiten der eingehenden Nachrichten.
    5. private void Listen(object o) {
    6. var Connection = (Connection) o;
    7. while (true) {
    8. try {
    9. var Content = Connection.streamr.ReadLine();
    10. // Nachricht anzeigen oder was auch immer
    11. } catch {
    12. // Die Verbindung ist weg, hier die Verbindung ANSTÄNDIG! beenden, evtl ne Nachricht ausgeben.
    13. // Anständig beenden wäre z.B. sowas hier: https://github.com/defectively/defectively/blob/master/Defectively/Connection.cs#L98
    14. return;
    15. }
    16. }
    17. }


    Grüße
    Vainamo

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

    Oha, ich dachte, dass die Probleme bei 2x Button_Click kommen.
    Vainamo hat recht. Nach der Nachricht muss die Verbindung mindestens per client.close() geschlossen werden, sonst passiert da nix mehr.
    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.

    kayle schrieb:

    das mit Client.close hat das Problem gelöst

    Das ist der falsche Ansatz. Man erstellt nicht für jede Nachricht eine neue Connection!
    Sieh dir noch einmal meine Lösung an: Tcplistener funktioniert 1x

    Grüße
    Vainamo
    @Vainamo: Ich würde sagen: Es kommt drauf an. Wenn die Änderungen von verschiedenen Clients kommen bzw. allgmein: Der Server kommuniziert mit mehreren Clients, dann wäre es m.E. schon sinnvoll, wenn die Verbindung zum Client nach dem GUI-Änderungsbefehl geschlossen wird. Wenn es hingegen nur einen Client geben, sollte zwar die Verbindung erhalten bleiben, so wie Du geschrieben hast, es sollte aber auch in dem Server-Nebenthread bzw. in der Nachrichtenverarbeitungsschleife eine Möglichkeit eingebaut werden, dass der Client eine logout-nachricht an den Server schicken kann, damit die Verbindung geschlossen wird.
    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 Ein TCP Verbindungsaufbau benötigt mindestens 3 Pakete. Ein SYN, ein SYN/ACK und ein FIN Paket. Das ist unnötiger Traffic, wenn man die Connection jedes mal neu herstellt. Was das trennen angeht: Entweder über eine Logout-Nachricht oder der Client trennt die Verbindung einfach. Der Serverthread läuft dann von selbst in den Catch, trennt die Verbindung und beendet den Thread.

    @kayle Es laufen sowieso 2 Threads. Der GUI Thread und der Thread in dem der Server auf eingehende Verbindungen wartet. Aber du hast recht, es kommt dann für jede Connection ein neuer Thread hinzu. Wenn dir das zu unperformant erscheint (keine Angst, 100+ Connections sind problemlos möglich), kannst du auf einen Threadpool umsteigen oder dich an einer asynchronen Lösung versuchen.

    Grüße
    Vainamo
    Vollzitat entfernt. ~Trade

    Die Daten kommen von einem Datamatrix Scanner. Da kommen am Tag schon mal 3000 - 5000 "Strings" vom Scanner. Ich muss mich dann wohl mal mit dem Threadpool beschäftigen.

    Gruß Kay

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

    @kayle Vollzitate sind nicht gestattet vb-paradise.de/index.php/Terms/ §4 Abs 3f.

    Wenn es nur 1 Scanner ist, reicht es vollkommen aus einen eigenen Thread für die Connection zu erstellen. Da brauchst du keinen ThreadPool.

    Grüße
    Vainamo