TCP-Verbindung (Dauer)

  • Hallo!

    Nachdem ich das Forum studiert aber leider nichts zu dem Thema gefunden habe frage ich mal die Spezialisten:

    Wo will ich hin: Ein Serverprogramm das via TCP Daten empfängt und in ein Logfile speichert - gibt bereits und funktioniert
    Weiter gibt es einen Testclient der Daten schickt - funkt local als auch übers Netz!

    Jetzt kommt die Frage:

    Ich mache am Server ein Socket auf das lauscht auch ganz brav am Netz und wenn Daten kommen reagiert es wie gewollt darauf. ABER die Verbindung wird nicht nach gleich abgebaut (mit einem TCP-Monitor sieht man das). Kommt die nächste Verbindung wird ein Socket aufgemacht usw usw.

    Da jetzt die Clients mehr oder weniger gleichzeitig die Daten schicken werden so hunterte Ports am Server belegt und im schlimmsten Fall kracht es dann!

    Ich habe versucht mit der Option TCPTimeout die Zeit zu verkürzen damit das Port schneller freigegeben wird, aber das scheint hier wirkungslos zu sein!

    Nur um einen Eindruck zu bekommen ein Screenshot (die Verbindungen sind auch Minuten nachdem der Client beendet worden ist noch da):

    Ist das einfach so (weil Windows so ist) oder gibt es da noch einen anderen Trick? Oder wäre hier UDP besser geeignet?

    Sicherheitshalber meine beiden Scripts:

    Server:

    [autoit]

    ;Druckerdaten erfassung - Server

    [/autoit][autoit][/autoit][autoit]

    #include <advfha_proc.au3>
    #include <EditConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    local $logfile = "d:\printer.log"
    local $datei = FileOpen ($logfile, 1)

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    ;TCP-Service starten
    TCPStartup ()

    [/autoit][autoit][/autoit][autoit]

    local $ip=@ipaddress1
    local $port = 2000
    local $text=""
    local $senderip

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    local $socket = TCPListen ($ip,$port, 2048)
    local $socketid = 0

    [/autoit][autoit][/autoit][autoit]

    While 1
    $socketid = TCPAccept($socket)
    If $socketid >= 0 Then
    $senderip = SocketToIP ($socketid)
    local $input = TCPRecv ($socketid, 4096)
    filewrite ($datei, @HOUR & ":" & @MIN & ":" & @SEC & " " & $senderip & " " & $input & @crlf)
    EndIf
    WEnd

    [/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit]

    func SocketToIP($SHOCKET)
    Local $sockaddr, $aRet

    [/autoit][autoit][/autoit][autoit]

    $sockaddr = DllStructCreate("short;ushort;uint;char[8]")

    [/autoit][autoit][/autoit][autoit]

    $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
    "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
    If Not @error And $aRet[0] = 0 Then
    $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
    If Not @error Then $aRet = $aRet[0]
    Else
    $aRet = 0
    EndIf

    [/autoit][autoit][/autoit][autoit]

    $sockaddr = 0

    [/autoit][autoit][/autoit][autoit]

    Return $aRet
    EndFunc ;==>SocketToIP

    [/autoit][autoit][/autoit][autoit][/autoit]


    Testclient:


    [autoit]

    ; TCP-Sender test

    [/autoit][autoit][/autoit][autoit]

    #include <advfha_proc.au3>

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    #include <ButtonConstants.au3>
    #include <EditConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <GuiIPAddress.au3>
    #include <WindowsConstants.au3>
    #include <GuiIPAddress.au3>

    [/autoit][autoit][/autoit][autoit]

    #Region ### START Koda GUI section ### Form=
    $Form1 = GUICreate("TCP-Client", 602, 347, 216, 659)

    [/autoit][autoit][/autoit][autoit]

    $Edit1 = GUICtrlCreateEdit("", 32, 56, 545, 217, $ES_READONLY)
    ;GUICtrlSetState(-1, $GUI_DISABLE)

    [/autoit][autoit][/autoit][autoit]

    global $Eingabe = GUICtrlCreateInput("Eingabe", 32, 296, 441, 21)
    $Senden = GUICtrlCreateButton("Senden", 496, 296, 75, 25)
    GUICtrlSetOnEvent(-1, "senden")

    [/autoit][autoit][/autoit][autoit]

    $IPAddress1 = _GUICtrlIpAddress_Create($Form1, 32, 16, 130, 21)
    _GUICtrlIpAddress_Set($IPAddress1, "x.x.x.x")

    [/autoit][autoit][/autoit][autoit]

    $Port = GUICtrlCreateInput("2000", 168, 16, 49, 21)
    ;GUICtrlSetData($Port, "2000")

    [/autoit][autoit][/autoit][autoit]

    GUISetState(@SW_SHOW)

    [/autoit][autoit][/autoit][autoit]

    #EndRegion ### END Koda GUI section ###
    Opt("GUIOnEventMode", 1)

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    ;TCP-Service starten
    TCPStartup()

    [/autoit][autoit][/autoit][autoit]

    global $socket_jn = -1
    global $socketid = 0

    [/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit]

    While 1
    GUISetOnEvent($GUI_EVENT_CLOSE, "Ende")
    WEnd

    [/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit]

    func Ende()
    exit
    endfunc ;==>Ende

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    func senden()

    [/autoit][autoit][/autoit][autoit]

    $kanal = GUICtrlRead($Port)
    $ip = _GUICtrlIpAddress_Get($IPAddress1)

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    local $text = GUICtrlRead($Eingabe)
    local $alttext = GUICtrlRead($Edit1)

    [/autoit][autoit][/autoit][autoit]

    $socketid = TCPConnect($ip, $kanal)
    local $ret = TCPSend($socketid, $text)
    TCPCloseSocket($socketid)

    [/autoit][autoit][/autoit][autoit]

    $text = $alttext & @crlf & ">" & @HOUR & ":" & @MIN & ":" & @SEC & " on " & $ip & ":" & $kanal & " SocketID:" & $socketid & " " & $text

    [/autoit][autoit][/autoit][autoit]

    GUICtrlSetData($Edit1, $text)
    GUICtrlSetData($Eingabe, "")

    [/autoit][autoit][/autoit][autoit]

    endfunc ;==>senden

    [/autoit][autoit][/autoit][autoit][/autoit]

    Einmal editiert, zuletzt von Racer (22. April 2014 um 11:08)

  • Zwei Dinge...

    Server: Du schließt den Socket nicht, also kaum verwunderlich, dass dieser noch ewig rumgammelt
    Client: Wozu setzt du millionenfach das $GUI_EVENT_CLOSE in deiner while Schleife? Warum setzt du Events für Controls und aktivierst den oneventmode erst danach?

  • Zwei Dinge...
    Server: Du schließt den Socket nicht, also kaum verwunderlich, dass dieser noch ewig rumgammelt
    Client: Wozu setzt du millionenfach das $GUI_EVENT_CLOSE in deiner while Schleife? Warum setzt du Events für Controls und aktivierst den oneventmode erst danach?

    Hallo!

    Danke für deine Antwort:

    zu Server: Naja, wenn ich den Socket schliesse kann ja keiner mehr was schicken!

    oder habe ich laut Doku etwas falsch verstanden:

    1) TCP starten
    2.) Socket aufmachen
    3.) lauschen am Netz und bei Eingang darauf Daten verabeiten

    Es Webserver lauscht ja auch, mach dann für den Datentransfer ein Socket auf und baut es sofort wieder ab... so was würde ich hier brauchen.
    Oder kann ich das von Client her aus irgendwie sagen das die Verbindung gecloset werden kann?


    zu Client: stimmt, ist aber nur ein Testclient der dann wieder weg kommt! Ich habe den Client nur damit ich mit irgendwas Daten senden kann! Bin mit der GUI noch nicht so sattelfest!

    lg
    Racer

  • Ahja und natürlich sollte man nicht nur unbenutzte Sockets schließen, sondern bei Programmende auch

    [autoit]

    tcpshutdown()

    [/autoit]

    aufrufen, was letztlich alles sauber aufräumen sollte.

  • Ahja und natürlich sollte man nicht nur unbenutzte Sockets schließen, sondern bei Programmende auch

    [autoit]

    tcpshutdown()

    [/autoit]

    aufrufen, was letztlich alles sauber aufräumen sollte.

    Ok, jetzt hast Du es geschafft - ich stehe entgültig am Schlauch ?( ! Wie schliesse ich Sockets die nicht gebaucht werden? Ich mache ja nur eines auf und das brauche ich in alle Ewigkeit.... daher auch kein TCPShutdown.....

  • [autoit]


    local $socket = TCPListen ($ip,$port, 2048)
    local $socketid = 0

    [/autoit][autoit][/autoit][autoit]

    While 1
    $socketid = TCPAccept($socket)
    If $socketid >= 0 Then
    $senderip = SocketToIP ($socketid)
    local $input = TCPRecv ($socketid, 4096)
    filewrite ($datei, @HOUR & ":" & @MIN & ":" & @SEC & " " & $senderip & " " & $input & @crlf)
    EndIf
    WEnd

    [/autoit]

    Was ich meinte ist der Verbindungssocket im Server. Dieser ist bei dir in der Variable $socketid gespeichert und hat nichts mit deinem $socket zu tun, welcher neue Verbindungen annehmen kann. Es ist aber richtig, wenn du den Verbindungsocket $socketid mit tcpclosesocket() schließt kann der client nichts mehr an den Server senden und muss eine neue Verbindung aufbauen. Wenn du also mehrere aktive Verbindungen haben willst braucht du statt einer Variable ein Array für die Verbindungssockets. Du könntest hier dann über dein Protokoll zur Kommunikation auch Regeln festlegen, damit Client und Server sich einigen können wie lange die Verbindung bestehen soll und wann es Zeit ist die Sockets auf beiden Seiten zu schließen. In deinem Beispiel trennt der Client aber ohenhin nach einmaligem senden, also kann auch der Server den Socket killen sobald die Daten empfangen wurden.


    EDIT:

    tcpshutdown bei "Programmende" hatte ich geschrieben, die Ewigkeit sollte spätestens dann vorbei sein wenn der Client oder der Server beendet wurde, hier verwendet man dann natürlich ein shutdown der TCP Funktionalität, genauso wie du bei Programmstart ein tcpstartup verwendest.

  • Jetzt ist der Groschen gefallen!

    Ich habe jetzt meine Serverteil so geändert:

    [autoit]

    While 1
    $socketid = TCPAccept($socket)
    If $socketid >= 0 Then
    $senderip = SocketToIP ($socketid)
    local $input = TCPRecv ($socketid, 4096)
    filewrite ($datei, @HOUR & ":" & @MIN & ":" & @SEC & " " & $senderip & " " & $input & @crlf)
    TCPCloseSocket ($socketid)
    EndIf
    WEnd

    [/autoit]

    Und siehe da, es wird nur das eine Port (in meinen Fall TCP 2000) angezeigt!

    Super, vielen Dank!

    Leider geht das nicht so ganz aus der deutschen Doku hervor, denn man kann das leicht (so wie ich) so interpredieren, das damit der Socket (der lauscht) wieder geschlossen wird!!!!

    lg
    Racer

    PS: TCPShutdown kommt noch - versprochen ;)

  • Leider geht das nicht so ganz aus der deutschen Doku hervor, denn man kann das leicht (so wie ich) so interpredieren, das damit der Socket (der lauscht) wieder geschlossen wird!!!!


    Das hat nichts mit einem Fehler in der Hilfe zu tun. Dein Fehler ist lediglich ein Resultat aus der Tatsache, dass du TCP noch nicht verstanden hast bzw. hattest.
    Nebenbei bemerkt: Sendet der aktuelle Client nicht in ein paar Sekunden bzw Millisekunden seine Daten wird die Verbindung vom Server her abgebrochen ob wohl der Client noch nicht senden konnte. Außerdem wird alles größer 4096 einfach abgeschnitten...

    LG
    Christoph :)


  • Das hat nichts mit einem Fehler in der Hilfe zu tun. Dein Fehler ist lediglich ein Resultat aus der Tatsache, dass du TCP noch nicht verstanden hast bzw. hattest.
    Nebenbei bemerkt: Sendet der aktuelle Client nicht in ein paar Sekunden bzw Millisekunden seine Daten wird die Verbindung vom Server her abgebrochen ob wohl der Client noch nicht senden konnte. Außerdem wird alles größer 4096 einfach abgeschnitten...


    Lieber Christoph!

    Ich habe weder was von einem Fehler in der Doku geschrieben noch mag ich es wenn Du versucht mir zu sagen was ich kann oder nicht! Deine Aussage hat nichts mit meiner gestellten Frage zu tun! Vielleicht hast Du die Doku anders verstanden als ich - ok! Aber bitte unterlasse solche Bemerkungen das ich (ohne das Du mich kennst) nichts von TCP verstehe!

    Die Doku ist nicht perfekt, aber ich bin trotzdem denen sehr Dankbar die sich die Mühe machen und eine Übersetztung schreiben! Wenn dann was nicht ganz klar ist gibt es immer noch ein Forum, und in diesen Fall hat mir misterspeed sehr schnell und professionell geholfen (vielen Dank nochmal an der Stelle)!

    lg
    Racer