TCP Server [Grundgerüst]

  • Da Server (besonders unter AutoIt-Neulingen) immer wieder ein Problem darstellen,
    und ich hier auch schon einige "seltsame" Konstruktionen gesehen habe,
    wollte ich einfach mal zeigen, wie ich einen TCP Server programmieren würde:

    [autoit]

    Local $Server, $Client = -1, $Data ; die wichtigsten Variablen

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

    TCPStartup() ; TCP starten

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

    $Server = TCPListen(@IPAddress1, 1337) ; Server starten
    If @error Then
    ; Information an den Benutzer ausgeben, dass der Server nicht gestartet werden konnte
    TCPShutdown()
    Exit
    EndIf

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

    Do
    If ($Client > 0) Then ; überprüfen, ob schon ein Client verbunden ist
    $Data = TCPRecv($Client, 1024) ; Daten vom Client empfangen
    If @error Then ; Client nicht mehr verbunden
    $Client = -1 ; $Client zurücksetzen
    ElseIf (StringLen($Data) > 0) Then ; Client hat etwas gesendet
    ; Daten verarbeiten
    TCPSend($Client, $Data) ; Antwort an den Client schicken
    EndIf
    Else ; noch kein Client verbunden
    $Client = TCPAccept($Server) ; eingehende Verbindung akzeptieren
    EndIf
    ; andere wichtige Sachen, zum Beispiel irgendwas um die Schleife zu beenden
    Until False
    TCPCloseSocket($Client) ; Verbindung zum Client trennen
    TCPCloseSocket($Server) ; Server beenden
    TCPShutdown() ; TCP beenden
    Exit ; Skript beenden

    [/autoit][autoit]

    Local $Server, $Client[100], $i, $Data ; die wichtigsten Variablen
    For $i = 0 To 99
    $Client[$i] = -1 ; -1 = nicht verbunden
    Next

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

    TCPStartup() ; TCP starten

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

    $Server = TCPListen(@IPAddress1, 1337) ; Server starten
    If @error Then
    ; Information an den Benutzer ausgeben, dass der Server nicht gestartet werden konnte
    TCPShutdown()
    Exit
    EndIf

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

    $i = 0 ; $i zurücksetzen
    Do
    If ($Client[$i] > 0) Then ; überprüfen, ob der Client schon verbunden ist
    $Data = TCPRecv($Client[$i], 1024) ; Daten vom Client empfangen
    If @error Then ; Client nicht mehr verbunden
    $Client[$i] = -1 ; $Client zurücksetzen
    ElseIf (StringLen($Data) > 0) Then ; Client hat etwas gesendet
    ; Daten verarbeiten
    TCPSend($Client[$i], $Data) ; Antwort an den Client schicken
    EndIf
    Else ; Client noch nicht verbunden
    $Client[$i] = TCPAccept($Server) ; eingehende Verbindung akzeptieren
    EndIf
    $i += 1 ; $i um 1 erhöhen, damit beim nächsten Durchlauf der Schleife der nächste Client verarbeitet werden kann
    If ($i = UBound($Client)) Then $i = 0 ; nach dem letzten Client wieder von vorne beginnnen
    ; andere wichtige Sachen, zum Beispiel irgendwas um die Schleife zu beenden
    Until False
    TCPCloseSocket($Client) ; Verbindung zum Client trennen
    TCPCloseSocket($Server) ; Server beenden
    TCPShutdown() ; TCP beenden
    Exit ; Skript beenden

    [/autoit]
  • Ich möchte an dieser Stelle nur einmal anmerken, dass eine solche Konstruktion (auf Client- und Serverseite) zu sehr großen Problemen führen kann...

    [autoit]

    $Data = TCPRecv($Client, 1024)

    [/autoit]

    Denn was passiert wenn die Gegenseite gleich mehrere Pakete hintereinander schickt oder wenn ein Paket größer als 1024 Zeichen schickt? Genau es kommt zu Fehlern in der Verarbeitung! Deshalb sollte die Rückgabe von TCPRecv() stehts in einen Buffer geschrieben werden, welcher dann nach vollständigen Paketen abgesucht wird. Wenn diese dann abgearbeitet sind werden eben diese aus dem Buffer entfernt und übrig bleibt der Anfang des noch noch nicht vollständig angekommenen Paketes. ;)

    LG
    Christoph :)

  • Stimmt natürlich auch wieder, wobei ein geeigneter Wert für maxlen in einigen Anwendungen imho auch funktionieren sollte ohne Probleme zu verursachen. Aber du hast natürlich Recht.
    Edit: Ein Chatserver wäre eine solche Anwendungsmöglichkeit.