TCP "Chat" | Anfänger

  • Hi :)
    ich würde gerne etwas über TCP erlernen, bin jedoch noch ein totaler Anfänger und habe im Prinzip keinen blassen Schimmer darüber.

    Jetzt wollte ich sozusagen einen "Chat" erstellen, der eine Kommunikation zwischen 2 PCs ermöglicht.
    Wie genau soll das gehen?
    Ich habe jetzt mal einen Server und einen Client erstellt.

    Server:

    Spoiler anzeigen
    [autoit]

    TCPStartup()

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

    $mainsocket = TCPListen("127.0.0.1", 4321)

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

    While 1 ; Endlosschleife
    $acceptedSocket = TCPAccept($mainsocket)

    If $acceptedSocket <> -1 Then
    $receivedData = TCPRecv($acceptedSocket, 1024)
    MsgBox(64, "Nachricht empfangen!", "Es wurde eine Nachricht empfangen: " & $receivedData)
    TCPCloseSocket($acceptedSocket)
    EndIf
    WEnd

    [/autoit]

    Client:

    Spoiler anzeigen
    [autoit]

    TCPStartup() ; TCP wird initialisiert

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

    $socket = TCPConnect("127.0.0.1", 4321) ; Versucht eine Verbindung zum Server aufzubauen und speichert die SocketID in "$socket" ab

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

    If $socket = -1 Then ; Wenn $socket = -1 ist, Fehlermeldung ausgeben
    MsgBox(16, "Error", "Die Verbindung zum Server konnte nicht hergestellt werden!")

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

    $sendedBytes = TCPSend($socket, "Test")
    If $sendedBytes = 0 Then
    MsgBox(16, "Error", "Das Paket konnte nicht gesendet werden.")
    EndIf

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

    TCPCloseSocket($socket)
    TCPShutdown()

    [/autoit]

    Wenn man auf einem PC zuerst den Server startet und dann den Client funktioniert es natürlich. Aber wie funktioniert das Ganze, wenn man es über 2 verschiedene PCs machen will?

    Wenn ihr mich zusätzlich noch auf TCP_Anfänger_Tuts verweisen könntet, wäre ich euch ebenfalls noch dankbar :)

  • Zitat

    Wenn man auf einem PC zuerst den Server startet und dann den Client funktioniert es natürlich. Aber wie funktioniert das Ganze, wenn man es über 2 verschiedene PCs machen will?


    Dann funktioniert es genauso, du musst halt nur die IP bei TCPListen vom Server verändern. Ich selber kann auch nur vermuten, warum man dies tun muss, aber ich habe dazu schonmal ein endlos langen Monolog geschrieben. Ah, ich habs über Google gefunden. Wie gesagt: Das ist nur eine Vermutung, aber als Modellvorstellung funktioniert es bis jetzt ganz gut:


    Wenn du also im Intranet eine Verbindung herstellen willst, musst du als IP deine interne Verwenden (192.168.x.x). Wenn du über das Internet (achtung, da steht dein Router im Weg) verbinden willst, musst du auf jeden Fall die globale IP deines Routers beim Client angeben und AFAIK die interne IP beim Server. (Musst du halt Rumprobieren)
    Hoffe es hilft, @night@

    PS: Ich habe es mir nicht komplett angeguckt, aber die Tutorials von blog4it sind eigentlich immer gut. Klick

    Einmal editiert, zuletzt von @night@ (22. Januar 2012 um 15:55)

  • Zitat

    du musst halt nur die IP bei TCPListen vom Server verändern


    eben nicht... Die IP bei TCPListen beim Server kannst du eigentlich immer auf @IPAddress1 lassen, egal ob intern oder öffentlich.
    Was sich verändert ist TCPConnect beim Client. Das verwendet entweder die interne Addresse vom Server oder die öffentliche(und die verändert sich zudem wenn sich dein Router neu einwählt).
    Und immer schön PortForwarding nicht vergessen, wenn du über das Internet arbeitest:)

    Edit: @night@:
    Zu deinem Problem: Du musst natürlich einheitlich arbeiten. Entweder du connectest zum localhost und hörst den dann auch ab, oder du nimmst die intere IP im lokalen Netzwerk, aber das sind zwei verschiedene Dinge. Ich würde aber immer die Addresse im Intranet bei Server nehmen, da auch dein Router an diese Addresse weiterleitest und so kannst du den Server eigentlich unverändert lassen egal ob er im Intranet oder im Internet läuft

    Zitat

    You just keep on trying 'till you run out of cake. ;)


    [STEAM] Source UDF

    2 Mal editiert, zuletzt von K4z (22. Januar 2012 um 16:10)

  • Zitat


    eben nicht... Die IP bei TCPListen beim Server kannst du eigentlich immer auf @IPAddress1 lassen, egal ob intern oder öffentlich.


    eben nicht... Wenn du bei TCPListen 127.0.0.1 angibst, dann wird es keinem anderen PC innerhalb deines Netzwerkes möglich sein zu dir zu connecten. Der zweite Teil deiner Aussage stimmt jedenfalls. Ich wollte nur mal versuchen das zu erklären. Vielleicht melden sich ja noch Andy oder Bugfix und lösen das Problem auf ;)

    €dit:

    Zitat


    Zu deinem Problem: Du musst natürlich einheitlich arbeiten. Entweder du connectest zum localhost und hörst den dann auch ab, oder du nimmst die intere IP im lokalen Netzwerk, aber das sind zwei verschiedene Dinge. Ich würde aber immer die Addresse im Intranet bei Server nehmen, da auch dein Router an diese Addresse weiterleitest und so kannst du den Server eigentlich unverändert lassen egal ob er im Intranet oder im Internet läuft


    Genau das wollte ich ja auch sagen. Ich wollte halt nur mal wissen, ob meine Vermutung mit der Destination-IP im IP-Paket richtig ist. Mit der Aussage "Du musst halt nur dei IP ändern", wollte ich ihm darauf aufmerksam machen, dass man nicht die IP "127.0.0.1" für 2 verschiedene Rechner benutzen kann.

    Einmal editiert, zuletzt von @night@ (22. Januar 2012 um 16:25)

  • Bei solchen Themen redet man oft aneinander vorbei,,,,
    Also ich hab das eben so verstanden, dass wenn du 127.0.0.1, was ja nichts anderes als localhost ist, abhörst dann kann ja auch nichts empfangen werden, dass für die lokale IP-Addresse bestimmt ist. Da ist daann deine Vermutung mit der Destination-IP gar nicht so falsch. Aber wie gesagt, dass Problem hat man erst gar nicht, wenn man nicht mit localhost sonder mit der NetzwerkIP arbeitet.
    Aber ich bin auch mal gespannt was hier die richtigen Experten zu sagen ham:D

  • Zitat

    Also ich hab das eben so verstanden, dass wenn du 127.0.0.1, was ja nichts anderes als localhost ist, abhörst dann kann ja auch nichts empfangen werden, dass für die lokale IP-Addresse bestimmt ist. Da ist daann deine Vermutung mit der Destination-IP gar nicht so falsch. Aber wie gesagt, dass Problem hat man erst gar nicht, wenn man nicht mit localhost sonder mit der NetzwerkIP arbeitet.


    Jetzt haben wir uns glaub ich gedanklich getroffen :D Ich wollte halt nur mal wissen, warum das so ist und ob meine Vermutung stimmt.

  • okay,... jetzt bin ich leicht verwirrst :D

    Also, wenn ich jetzt beim Server (auf meinem PC) die IP Adresse des PCs angebe (in autoIt), der den Client hat und beim Client meine IP-Adresse angegeben hat, müsste das ganze funktionieren? :)

    Im Prinzip ist der Server jetzt ja der Empfänger und der Client der Sender... also geht das dann so? Oder muss ich noch irgendwo was freischalten?


    Danke an alle, die sich schon mal die Mühe gemacht haben :)

  • Zitat

    Im Prinzip ist der Server jetzt ja der Empfänger und der Client der Sender... also geht das dann so? Oder muss ich noch irgendwo was freischalten?


    Server (to serve = zustellen): Nimmt Verbindungen an.
    Client (client=Kunde): Fragt Verbindungen an

    Was die danach miteinander machen ist egal ;) Dein Server wartet per TCPListen und TCPAccept auf Clients, die sich verbinden wollen.
    Dein Client fragt per TCPConnect eine Verbingung an.

    Benutze bei der IP von TCPListen einfach immer @IPAddress1:

    [autoit]

    TCPListen(@IPAddress1, 1234)

    [/autoit]


    @IPAddress1 beinhaltet immer deine interne IP (z.B. 192.168.x.x)

    Die IPAdresse 127.0.0.1 bezeichnet immer deinen eigenen PC. Da gab es schon ein paar sehr interessante Verwechselungen.

  • Zitat

    was soll ich eig. dann als Port angeben? :)


    Eigentlich alle, aber alle Ports von 0-1023 sind standartisiert. Du kannst dort zwar auch deine Programme laufen lassen, aber es wäre unüblich.
    Sinnvoller Kram zum Lesen

    Zitat von Allwissendes Wikipedia

    Ports sind 16-Bit-Zahlen (Portnummern) und reichen von 0 bis 65535. Ports von 0 bis 1023 sind reserviert[1] und werden von der IANA vergeben, z. B. ist Port 80 für das im WWW verwendete HTTP reserviert. Das Benutzen der vordefinierten Ports ist nicht bindend. So kann jeder Administrator beispielsweise einen FTP-Server (normalerweise Port 21) auch auf einem beliebigen anderen Port laufen lassen.


    Wei schon gesagt: Es steht dir frei zur Wahl die Ports von 0 bis 65535 zu benutzen, aber es wurden zur Übersicht Standards festgelegt. (FTP-Server = Port 21; HTTP-Server = Port 80 => Allgemeinbildung FTW)
    mfg @night@

  • bei mir funktioniert das ganze nicht so ganz
    Wenn vlt. jemand meinen Quellcode nehmen könnte und ihn so ausrichten könnte, dass das ganze funktioniert.
    Bzw. das was man beim Client / Server als Eingabewert hat vlt. markieren und genau erklären wie ich zu diesem Eingabewert komme?

    Am Ende sollte es halt eine Information von einem PC (auf dem der Client ist) zum anderen PC (auf dem der Server ist) schicken können. Nichts weiter :)

  • Hallo life2play, dein Code ist nach meiner Meinung nicht gerade sehr gut programmiert, sollte aber funktionieren:
    Server:

    Spoiler anzeigen
    [autoit]

    TCPStartup()

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

    $mainsocket = TCPListen(@IPAddress1, 4321)

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

    While 1 ; Endlosschleife
    $acceptedSocket = TCPAccept($mainsocket)

    If $acceptedSocket <> -1 Then
    $receivedData = TCPRecv($acceptedSocket, 1024)
    MsgBox(64, "Nachricht empfangen!", "Es wurde eine Nachricht empfangen: " & $receivedData)
    TCPCloseSocket($acceptedSocket)
    EndIf
    WEnd

    [/autoit]


    Client:

    Spoiler anzeigen
    [autoit]

    TCPStartup() ; TCP wird initialisiert

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

    $socket = TCPConnect(@IPAddress1, 4321) ; Versucht eine Verbindung zum Server aufzubauen und speichert die SocketID in "$socket" ab

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

    If $socket = -1 Then ; Wenn $socket = -1 ist, Fehlermeldung ausgeben
    MsgBox(16, "Error", "Die Verbindung zum Server konnte nicht hergestellt werden!")
    EndIf

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

    $sendedBytes = TCPSend($socket, "Test")
    If $sendedBytes = 0 Then
    MsgBox(16, "Error", "Das Paket konnte nicht gesendet werden.")
    EndIf

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

    TCPCloseSocket($socket)
    TCPShutdown()

    [/autoit]

    Wenn du beim Server die IP @IPAddress1 angibst, musst du sie auch beim Client ändern.
    Ich benutze zum Debuggen oftmals Telnet, das ist ein mitgeliefertes Programm von Microsoft mit dem du TCP-Verbindungen aufbauen kannst. Es ist sehr simpel und schlicht, aber zum Testen reicht es mir meist.
    Unter Windows 7 musst du es erst aktivieren. Dort wirst du auch das Problem erkennen. Da die Funktion TCPRecv() nicht wartet, wird dein Server direkt nach dem Verbindungsaufbau eine leere MsgBox ausgeben. Eine häufig verwendete Lösung ist eine Schleife:

    Spoiler anzeigen
    [autoit]

    TCPStartup()

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

    $mainsocket = TCPListen(@IPAddress1, 4321)

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

    While 1 ; Endlosschleife
    $acceptedSocket = TCPAccept($mainsocket)

    If $acceptedSocket <> -1 Then
    Do ;beginn der schleife
    $receivedData = TCPRecv($acceptedSocket, 1024) ;TCPRecv wartet nicht auf Pakete. Falls kein Paket vorhanden ist, wird es nichts zurückgeben
    until NOT $receivedData = "" ;wir warten solange, bis wir ein Paket erhalten haben
    MsgBox(64, "Nachricht empfangen!", "Es wurde eine Nachricht empfangen: " & $receivedData)
    TCPCloseSocket($acceptedSocket)
    EndIf
    WEnd

    [/autoit]

    Dies ist schonmal eine relativ gute Lösung. Wenn wir nun aber Telnet verwenden, werden wir sehen, dass absolut jeder getippte Buchstabe sofort versendet wird. Wenn wir Enter drücken, wird ein @crlf an deinen Server gesendet.
    Lösung: Wir empfangen solange, bis ein @crlf im Paket enthalten ist.

    Spoiler anzeigen
    [autoit]

    TCPStartup()

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

    $mainsocket = TCPListen(@IPAddress1, 4321)

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

    While 1 ; Endlosschleife
    $acceptedSocket = TCPAccept($mainsocket)

    If $acceptedSocket <> -1 Then
    $receivedData = "" ;wir resetten unsere Variable für die Pakete
    Do ;beginn der schleife
    $receivedData &= TCPRecv($acceptedSocket, 1024) ;man beachte das &= ;)
    until StringInStr($receivedData, @crlf) ;wir warten solange, bis wir ein man in Telnet ENTER gedrückt hat. Wir wollen schliesslich die ganze Naricht ;)
    MsgBox(64, "Nachricht empfangen!", "Es wurde eine Nachricht empfangen: " & $receivedData)
    TCPCloseSocket($acceptedSocket)
    EndIf
    WEnd

    [/autoit]


    Ich persönlich finde es gut, wenn jedes Paket mir @crlf abgeschlossen wird, weil so nicht mehrere Pakete in eine Variable kommen können. (Musst du nicht verstehen, aber irgendwann wirst du so komische Bugs bemerken die nicht umbedingt angenehm sind ;) )
    DEshalb ändern wir im Client:

    Spoiler anzeigen
    [autoit]

    $sendedBytes = TCPSend($socket, "Test" & @crlf) ;wir schliessen das Paket mit @crlf ab!

    [/autoit]

    Die zweite Lösung finde ich eleganter, aber das ist deine Sache. Nimm lieber das, was du verstehst.

    €dit: Wie bin ich eigentlich von der Frage auf Telenet gekommen ? :D Egal, ich lass das mal hier stehen.