TCP Filetransfer

  • Hallo,

    ich habe schon viele Threads durchgekaut und bin zu keiner Lösung gekommen.
    Für einen GameServer Scripte ich gerade ein 'Remote Administration Tool' - sodass wir über ein kleines Programm die Spieler überwachen (rauswerfen, sperren etc.) können.
    Der GameServer ist gemietet und nur auf MW3 abgestimmt, d.H. ich müsste 2 Programme (Server & Client) schreiben.
    Zuerst dachte ich, ich könnte das ganze über FTP & Textfiles machen, doch da wäre TCP wohl ein wenig besser.
    Nun zu meinem Problem.

    [autoit]

    TCPStartup()

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

    $Connection = TCPListen("192.168.2.101", 4321)
    ;~ $Connection = TCPConnect("192.168.2.108", 4321)
    If $Connection < 0 Then
    MsgBox(16, "Error", "Konnte keine Verbindung herstellen!")
    _Exit()
    EndIf

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

    While 1
    $Resv = TCPRecv($Connection, 2)
    If @error Then
    MsgBox(16, "Error", "Verbindung unterbrochen!")
    _Exit()
    EndIf
    If $Resv = "SF" Then
    While 1
    $Resv = TCPRecv($Connection, 2048, 1)
    If @error Then
    FileWrite(@ScriptDir & "\permanent.txt", $Resv)
    MsgBox(16, "Error", "Verbindung unterbrochen!")
    _Exit()
    EndIf
    FileWrite(@ScriptDir & "\permanent.txt", $Resv)
    WEnd
    EndIf
    WEnd

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

    Func _Exit()
    TCPShutdown()
    Exit
    EndFunc ;==>_Exit

    [/autoit]

    Erstmal verstehe ich nicht warum Server & Client die IP des Servers angeben müssen (der Server hat im Netzwerk die 192.168.2.101, der Client 192.168.2.108 ).

    So. Bei dem Script oben fliege ich an der ersten Haltestelle raus "Konnte keine Verbindung herstellen". An der Firewall liegts nicht. Ich konnte vorher mit einem abgeänderten Code auch schon einen Text an den Server Senden.

    2 Mal editiert, zuletzt von juloko1 (20. August 2012 um 13:43)

  • Soo ich habe mich mal schnell an ein Beispiel gesetzt, was dir die verschiedenen Funktionen hoffentlich genauer erklären dürfte...
    Es besteht aus einem Server- und einem Client-Script:

    Spoiler anzeigen

    Server

    [autoit]

    Global $MainSocket, $ClientSocket
    TCPStartup()
    Do
    $MainSocket = TCPListen(@IPAddress1, 4321) ; Wir versuchen auf dem Port 4321 einen TCP-Server zu erstellen
    Until Not @error
    ConsoleWrite('Server hört jetzt auf dem Port 4321' & @CRLF)
    While 1
    $ClientSocket = TCPAccept($MainSocket) ; Wir warten auf einen Verbindungsversuch eines Clients...
    If $ClientSocket <> -1 Then
    ; Ein Client ist nun mit unserem Server verbunden. Wir können mit ihm über das Socket $ClientSocket kommunizieren...
    While 1
    $Recv = TCPRecv($ClientSocket, 1024) ; Wir schauen nach, ob der Client uns über das Socket ein Paket gesendet hat...
    If @error Then ExitLoop ; Falls der Client die verbindung 'plötzlich' getrennt hat, gehen wir wieder in den 'Warten-Mode'
    If $Recv <> '' Then
    $Command = StringLower(StringLeft($Recv, StringInStr($Recv, '|') - 1))
    $Content = StringTrimLeft($Recv, StringInStr($Recv, '|'))
    ConsoleWrite('Paket empfangen: "' & $Recv & '"' & @CRLF & @TAB & 'Befehl: ' & $Command & @CRLF & @TAB & 'Parameter: ' & $Content & @CRLF)
    Switch $Command
    Case 'messageBox'
    MsgBox(64, 'Nachricht von Client:', $Content, 4)
    Case 'randomNumber'
    Sleep(250)
    TCPSend($ClientSocket, 'Z' & Random(1, 100, 1)) ; Hier wird ein Paket an den Client zurück gesendet!
    Case 'disconnect'
    ExitLoop
    Case 'shutdown_server'
    ConsoleWrite('Der Server wird nun beendet...' & @CRLF)
    TCPCloseSocket($ClientSocket)
    TCPShutdown()
    Exit
    Case Else
    ConsoleWrite('Unbekannter Befehl: "' & $Command & '"' & @CRLF)
    EndSwitch
    EndIf
    WEnd
    ; Verbindung wird geschlossen und wir beginnen damit wieder auf eine neue Verbindung zu warten...
    TCPCloseSocket($ClientSocket)
    EndIf
    WEnd

    [/autoit]
    Spoiler anzeigen

    Client

    [autoit]

    TCPStartup()
    ; Eingaben durch User:
    $Server_IP = InputBox('Server IP', 'Bitte geben sie die IP des Servers an:', @IPAddress1)
    $Server_Port = InputBox('Server Port', 'Bitte geben sie den verwendeten Port des Servers an:', 4321)
    ; Wir versuche uns mit dem Server zu verbinden:
    $MainSocket = TCPConnect($Server_IP, $Server_Port)
    If @error Then
    MsgBox(16, 'Fehler beim Verbinden', 'Entweder stimmen IP-Adresse/Port nicht, oder es ist bereits ein anderer Client mit dem Server verbunden...', 10)
    TCPShutdown()
    Exit
    EndIf
    MsgBox(64, 'Verbindung aufgebaut!', 'Es wurde erfolgreich eine Verbindung mit dem Server hergestellt...', 10)
    Sleep(1000)
    ; Wir lassen eine MessageBox, auf dem Server anzeigen...
    TCPSend($MainSocket, 'MessageBox|Hallo Server!')
    Sleep(4500)
    ; Nun senden wir ein Paket mit einem falschen Befehl an den Server...
    TCPSend($MainSocket, 'Gameserver-Start|Parameter1,Parameter2,Workingdir')
    Sleep(500)
    ; Wir fordern mit dem Befehl 'RandomNumber' eine Zufallszahl vom Server an...
    TCPSend($MainSocket, 'RandomNumber|Parameter der nicht beachtet wird...')
    Do
    $Recv = TCPRecv($MainSocket, 1024)
    Until $Recv <> '' ; Wir empfangen die Rückgabe des Servers auf unsere 'RandomNumber'-Anfrage...
    MsgBox(0, 'Rückgabe vom Server:', 'Vom Server generierte Zufallszahl: ' & $Recv, 10)
    ; Zu letzt trennen wir die Verbindung zum Server wieder 'sauber' (über unsere eingebaute Funktion...)
    TCPSend($MainSocket, 'Disconnect|')
    ; Wir warten kurz...
    Sleep(1500)
    TCPCloseSocket($MainSocket)
    Sleep(500)
    ; Okay nun werden wir uns noch einmal mit dem Server verbinden, um ihn auszuschalten:
    $MainSocket = TCPConnect($Server_IP, $Server_Port)
    If Not @error Then
    TCPSend($MainSocket, 'Shutdown_Server|')
    TCPCloseSocket($MainSocket)
    EndIf
    TCPShutdown()
    Exit

    [/autoit]

    Bitte denk daran, den Server immer VOR dem Client zu starten und die Inhalte der Inputboxen, so zu belassen, wie sie sind... ;)

    LG
    Christoph :)

  • Hey,

    danke für diese ausführliche Antwort!
    Kann eigentlich mehr als 1 Client auf den Server zugreifen? Wenn nicht, wie kann man das Lösen?

  • Freut mich, dass ich dir zumindest teilweise helfen konnte... :)
    Naja ich hatte schon befürchtet, dass du das fragst, aber bevor ich dir jetzt auch noch ein Beispiel für einen Multi-TCP-Server schreibe, kann ich ja einfach mal versuchen es dir so zu erklären, denn im Grunde ist es das selbe Prinzip wie bei nur einem Client. Allerdings musst du die Clients/ihre Sockets in einem Array abspeichern und sie dann eben wieder aus diesem löschen, wenn die Verbindung geschlossen wird/wurde. Außerdem musst dann natürlich auch in einer For-Schleife alle Client-Sockets auf neue Pakete überprüfen usw. Des Weitern musst du dir darüber im Klaren sein, dass du immer wenn du einem Client auch eine Antwort geben willst, dir merken musst welcher Client denn die Anfrage gestellt hat... ;) Das war jetzt mal da gröbste was du wissen musst. Außerdem kannst du dir ja einfach mal die Server-Scripte der zahlreichen TCP-Chats ansehen, welche natürlich auch fast alle eine Art "Multi-Server" enthalten...

    LG
    Christoph :)

  • Oh man, das hört sich ja für einen relativen AutoIT Amateur total easy an[/sarcasm]
    Ich bin hier gerade am rumbasteln und am überlegen wie man das sonst noch so lösen kann.
    Gäbe es da sonst noch eine 'umsetzbare', andere lösung? (via FTP oder sonstigem?)

  • Naja wirkliche Alternativen fallen zumindest mir da keine ein, es sei denn du machst es über UDP... :wacko:
    Versuch es doch einfach mal mit TCP und wenn du nicht weiter kommst, kannst du hier ja nachfragen... ;)
    Alternativ würde ich mich (aus Langeweile) anbieten dir den Server zu schreiben, wenn du mir sagen kannst, was genau er denn können soll... :D

    LG
    Christoph :)

  • Mhm, nein danke - ich möchte in das Unheil keine anderen Personen mit reinziehen :P

    Ich hatte mir zwischenzeitlich überlegt einen FTP Server als 'Brücke' zu nutzen.

    D.H. der Server lädt z.B. bei einer veränderung eine *.txt auf einen FTP Server, und die Clients laden diese runter. Ich könnte mir aber vorstellen das die Methode einiges an Datenvolumen frisst.
    Beim TCP hab ich mir sonst gedacht das es einen 'refresh' button gibt, sodass nicht dauerhaft Daten gesendet werden.


    Das mit dem Multi-TCP wird wohl nichts, ich habe mich heute zum ersten mal etwas mit TCP beschäftigt.

  • Mir fällt gerade eine UDF ein, mit der du wirklich einfach TCP Server erstellen kannst, auch welche, die mehrere Clients unterstützen. Wenn du willst, kann ich dir ja morgen mal ein kleines Beispiel schreiben.

    MfG, James

  • Das wär super nett, hauptsache ich kann damit als TCP Anfänger mit arbeiten :/

    Ach, ich denke, dass sollte zu schaffen sein :) :

    [autoit]

    #NoTrayIcon
    #include "TCPServer.au3" ; http://pastebin.com/Ht8vqAXN

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

    _TCPServer_RegisterEvent($TCPSERVER_RECEIVEDDATA, "ReceivedData")
    _TCPServer_Startup(@IPAddress1, 4321) ; Server auf Port 4321 starten

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

    While Sleep(100) ; leere Schleife, da die UDF alle Clients für uns verwaltet
    WEnd

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

    Func ReceivedData($socket, $data)
    Switch $data ; empfangene Daten
    Case "DATE"
    Return StringFormat("%02d.%02d.%04d", @MDAY, @MON, @YEAR)
    Case "TIME"
    Return StringFormat("%02d:%02d", @HOUR, @MIN)
    Case "SHUTDOWN"
    _TCPServer_Shutdown()
    Exit
    Case Else
    Return StringFormat('UNKNOWN COMMAND "%s"!', $data)
    EndSwitch
    EndFunc

    [/autoit]

    Wie du siehst, musst du nur die Daten verarbeiten, den Rest übernimmt die UDF.

    MfG, James

  • Hey, das sieht ja super aus!
    Zum versenden verwende ich gerade das Script hier, kannst du mir auch gerade verarbeiten wie ich die Returns verarbeite? oder muss ich dazu bei dem Client auch ein empfangsscript einbauen?

    [autoit]

    TCPStartup()
    $socket = TCPConnect("192.168.2.108", 4321)
    If @error Then Exit
    TCPSend($socket, "DATE")
    TCPCloseSocket($socket)
    TCPShutdown()

    [/autoit]


    Danke und liebe grüße :)

  • Um die Serverantwort zu verarbeiten nimmst du (wie in dem Client von Christoph54) TCPRecv.

    Zum Beispiel so:

    [autoit]

    MsgBox(64, "DATE", TCPRecv($socket, 1024))

    [/autoit]

    Das kannst du nach Zeile #4 einfügen.

  • Komisch, die Messagebox bleibt bei mir leer. Der Text der zurück kommt ist aber klartext, oder?

  • Alles klar, danke dir!

    Sind 1500msec normal? darunter kommt nichts zurück :o

    Wäre aber auch nicht weiter tragisch :D

    Ich versuch dann mal mein Glück, danke der Hilfe! Falls was ist melde ich mich

    EDIT: Sind mehrzeilige Returns möglich? (in Scite)

  • Hey,

    MW3 liegt auf einem gemieteten Server, die 2.5 Sekunden waren hier bei mir Zuhause im Netzwerk (Laptop über WLan und Tower über Lan). In der Praxis werde ich das erst in ein paar Tagen testen.

    4 Mal editiert, zuletzt von juloko1 (21. August 2012 um 19:22)

  • So etwas löst mann doch nicht über Sleep! ^^ In meinem Beispiel habe ich das nur der Verständlichkeit halber so gelöst... Normalerweise macht man das so, dass der Client/Server die Pakete 'unvorbereitet' empfängt. Das heißt, dass er nicht nur dann auf ein Paket wartet, wenn er gerade eines angefordert hat, sondern immer wenn er verbunden ist. So ist es kein Problem wenn die Gegenseite mal etwas schneller oder langsamer ist. Außerdem lassen sich dann auch problemlos viele Pakete/Befehle hinter einander losschicken und und und... ;)

    LG
    Christoph :)

  • Jetzt stehe ich gerade vor einem anderen Problem. Wie kann ich einen variablen Text vom Clienten an den Server senden?

    [autoit]

    $IN_CHATCONTENT = GUICtrlRead($IN_CHAT) ; Chateingabe
    TCPStartup()

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

    Global $socket = TCPConnect("192.168.2.108", 23330)

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

    TCPSend($socket, "CHATSEND") ; Wo klemm ich hier den Inhalt des Chats ran?

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

    TCPCloseSocket($socket)

    [/autoit]
  • BinDannMalWeg Du hast ja Recht, aber normalerweise bedient man so einen Server
    ja auch mit einem "richtigen" Client und nicht mit so einem 10-Zeilen-Testskript. ^^

    @juloko1
    Mein Server war natürlich nur ein Beispiel.
    Generell mache ich es auch immer so wie in dem Beispiel von Christoph,
    und zwar dass ich Befehle und Parameter durch "|" (oder irgendein anderes Zeichen) trenne.

    Der neue Server würde dann so aussehen:

    [autoit]

    ; by James1337
    ; TCPServer.au3: http://pastebin.com/Ht8vqAXN
    #NoTrayIcon
    #include "TCPServer.au3"

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

    _TCPServer_RegisterEvent($TCPSERVER_RECEIVEDDATA, "ReceivedData")
    _TCPServer_Startup(@IPAddress1, 4321)

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

    While Sleep(100)
    WEnd

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

    Func ReceivedData($socket, $data)
    $data = StringSplit($data, "|")
    Switch $data[1]
    Case "DATE"
    Return StringFormat("%2d.%2d.%4d", @MDAY, @MON, @YEAR)
    Case "TIME"
    Return StringFormat("%2d:%2d", @HOUR, @MIN)
    Case "SHUTDOWN"
    _TCPServer_Shutdown()
    Exit
    Case "SERVERMSG"
    If ($data[0] = 2) Then
    ConsoleWrite($data[2] & @LF)
    Return "OK"
    Else
    Return 'USAGE: "SERVERMSG|<MESSAGE>"'
    EndIf
    Case "CHATMSG"
    If ($data[0] = 2) Then
    _Send_Message_To_MW3_Chat($data[2])
    Return "OK"
    Else
    Return 'USAGE: "CHATMSG|<MESSAGE>"'
    EndIf
    Case Else
    Return StringFormat('UNKNOWN COMMAND "%s"!', $data)
    EndSwitch
    EndFunc

    [/autoit]


    In deinem Client könntest du das dann so umsetzen:

    [autoit]

    TCPSend($socket, "CHATMSG|deine Nachricht hier")

    [/autoit]

    MfG, James