Hallo Leute, habe das Gefühl das dieses Thema schon besprochen wurde, habe aber nichts finden können. Nun also zu meinem Problem: Ich habe einen Telnet-Server in C++ mit der Winsock lib geschrieben. Nach der Verbindung kann man dem Server einen Befehl schicken "Hi" und der antwortet dann mit "Gültiger Befehl" oder falls was anderes gesendet wird mit "Ungültiger befehl. Mit meinem Selbst geschriebenen C++ Client klappt das super. Wenn ich jetzt aber den Windows Telnet Client benutzte wird zwar korrekt verbindet und die verbindung bleibt auch bestehen aber der Befehlt wird nicht mehr richtig erkannt. Liegt der Fehler evt. an den Zeichensätzten ? und wie kann ich das Berichtigen? Lukas
gib dir doch am server einfach mal die rohdaten aus die du empfängst..der zeielnumbruch ist evtl anderst..
Zeichensätze und Telnet? Hmm, mir ist sowas nicht über den Weg gelaufen, aber wenn Du einen Server und Client selber programmiert hast, dann müsstest Du ja was in den RFCs dazu finden bzw. darüber gestolpert sein (denke ich). Wie schaut es mit deinem Client und einem anderem Telnet-Server aus. Funktioniert das? Eventuell lohnt es sich auch, mit Wireshark den Verkehr zu protokollieren und zu analysieren (falsche Byteorder???).
Ich lasse mir den gesendeten Text auch ausgeben und der ist exakt so wie er eigentlich sein sollte. Ich hänge euch mal meine server.cpp an.
Interessanter als zwei gleiche Headerdateien wäre die Bytefolge, die der telnet-Client sendet, indem einfach im Server jedes empfangene und jedes gesendete Byte (am besten Hexadezimal) ausgegeben wird, natürlich zusammen mit der Info, ob gelesen oder geschrieben. Deine Testkommunikation mit "Hi" und "Gültiger Befehl" würde dann etwa so aussehen:
1 | r: 0x48 |
2 | r: 0x69 |
3 | r: 0x0a |
4 | w: 0x47 |
5 | w: 0xfc |
6 | w: 0x6c |
7 | w: 0x74 |
8 | w: 0x69 |
9 | w: 0x67 |
10 | ... |
11 | w: 0x0a |
Evtl. noch mit Zeitstempel. Diese Ausgabe würde vermutlich die Lösung bringen. Ansonsten halt ein vollständiger Quelltext.
Immer noch nicht :-) Aber egal: > Ich lasse mir den gesendeten Text auch ausgeben und der ist > exakt so wie er eigentlich sein sollte. Wie lässt du dir die Texte ausgeben? Einfach als Text oder siehst du dir direkt die Hex-Codes der empfangenen Zeichen an? In solchen Fällen sind es nicht die sichtbaren Zeichen die interessant sind, sondern die Zeichen, die keine sichtbare Entsprechung haben aber etwas bewirken. Wie zb Carriage Return oder Line Feed. Auf die musst du dein Augenmerk richten.
Du schreibst "Telnet Server". Meinst du das wirklich so, also, implementierst du das Telnet Protokoll? Oder meinst du eher "TCP-Server" und verwendest nur einfach den telnet client zum testen, in Ermangelung eines besser passenden Client-Programms? (unter Unix würd' man z.B. "netcat" oder "sock" verwenden)
Hast du die im Abschnitt "TELNET COMMAND STRUCTURE" im RFC 854 beschrie- benen Befehle wenigstens dummymäßig in deinem Server implementiert? Der Client schickt nach dem Verbindungsaufbau jede Menge von diesen Befehlen zum Server.
AVR-Verwender schrieb im Beitrag #1894306: > Oder meinst du eher "TCP-Server" und verwendest nur einfach den telnet > client zum testen, in Ermangelung eines besser passenden Ja genau, das hab ich ganz vergessen zu sagen. Also ich benutze den Telnet Client nur zum aufbauen der verbindung. Es ist also eigentlich ein reiner TCP server nur mit dem Connecten über den Telnet client hab ich Probleme. Das wär mir allerdings sehr wichtig weil es auch Telnet clients für das iPhone gibt. Hier jetzt die server.cpp
das hier:
1 | //Empfangen und Ausgeben
|
2 | int BytesRec = recv(conn, Buffer, sizeof(Buffer), 0); |
3 | Buffer[BytesRec] = 0; |
4 | cout << "Client:" << Buffer << endl; |
5 | |
6 | //Befehle erkennen
|
7 | Befehl = Buffer; |
Funktioniert schonmal nicht. Dein Befehl muss nicht in einem ganzen Packet ankommen, theoretisch könntest du auch pro Buchstabe ein einzelpaket kriegen. (ist glaube ich default im windows-Telnet, damit jeder Tastendruck sofort ankommt, kann vom server aus per telnet-option verstellt werden) Du musst also recv solange aufrufen und buffern, bis du eine komplette Zeile empfangen hast, und dann diese überprüfen.
Lukas M. schrieb: > Ja genau, das hab ich ganz vergessen zu sagen. Also ich benutze den > Telnet Client nur zum aufbauen der verbindung. Es ist also eigentlich > ein reiner TCP server nur mit dem Connecten über den Telnet client hab > ich Probleme. Dann nimm netcat anstelle von telnet. > Das wär mir allerdings sehr wichtig weil es auch Telnet clients für das > iPhone gibt. Wenn es unbedingt telnet sein muss: s. mein Beitrag vom 13.10.2010 11:28 Auch den Rat von AVR-Verwender solltest du beherzigen.
AVR-Verwender schrieb im Beitrag #1894685: > das hier: >
1 | > //Empfangen und Ausgeben |
2 | > int BytesRec = recv(conn, Buffer, sizeof(Buffer), 0); |
3 | > Buffer[BytesRec] = 0; |
4 | > cout << "Client:" << Buffer << endl; |
5 | >
|
6 | > //Befehle erkennen |
7 | > Befehl = Buffer; |
8 | >
|
9 | >
|
> Funktioniert schonmal nicht. Dein Befehl muss nicht in einem ganzen > Packet ankommen, theoretisch könntest du auch pro Buchstabe ein > einzelpaket kriegen. > (ist glaube ich default im windows-Telnet, damit jeder Tastendruck > sofort ankommt, kann vom server aus per telnet-option verstellt werden) > > Du musst also recv solange aufrufen und buffern, bis du eine komplette > Zeile empfangen hast, und dann diese überprüfen. Und selbst wenn eine Zeile ein Paket ist, so ist die Kontrollausgabe unglücklich gemacht, weil man nämlich genau die neuralgischen White-Space Character wie Leerzeichen, Tab, Carriage Return, Line Feed eben nicht sieht. Das mindeste ist es * sich die Stringlänge noch mit ausgeben zu lassen. Wenn dann ein Text von "hi" keine strlen von 2 hat, dann ist noch irgendwo ein (meistens) ein \n mit von der Partie. * sich vor und hinter den String ein bekanntes Sonderzeichen zu setzen. zb cout << "Client: *" << Buffer << "*" << endl; Die Ausgabe muss dann
1 | *hi* |
lauten steht auf dem Schirm
1 | * |
2 | hi* |
dann war da ein \n vor dem hi steht dort
1 | *hi |
2 | * |
dann war das \n nach dem hi steht dort
1 | * |
2 | hi |
3 | * |
dann hat man 2 Stück \n im String, eines davor und eines dahinter * am besten wäre es allerdings den kompletten String als ASCII Codes auszugeben. Dann sieht man auf jeden Fall jegliche Sonderzeichen
1 | if( Befehl=="hi\n") |
Das ist ungeschickt. Sonderzeichen wie \n oder \r entfernt man aus dem String ehe die Auswertung losgeht. Auch führende und nachfolgende Leerzeichen. Ansonsten wird dein Benutzer keine Freude haben, wenn er hi eingibt und der Rechner versteht ihn nicht.
Nimm statt dem Telnet-Client doch putty. Da kann man auch im raw Modus verbinden. Oder wie schon gesagt netcat. Gibt es auch für Windows. Kann nur sein das der Virenscanner netcat als gefährliches Hackertool löscht.
Wie kann ich denn den Zeilen umbruch löschen? mit
1 | Befehl = Befehl.substr(0, Befehl.length()-2); |
komm ich zu keinem Ergebniss Liebe Grüße
Lukas M. schrieb: > komm ich zu keinem Ergebniss kein Ergebnis kann nicht sein, welches denn (auch wenn es ein unerwartetes war)? length()-1 würde die Sache eher treffen, wenn ein Zeichen abgeschnitten werden soll.
Wie oben schon mehrfach geschrieben wurde: Bring erstmal deine Empfangs-Schleife in Ordnung, Buffere den Input richtig. TCP bzw. das Sock-Interface gibt dir keine Garantie, wie zerstückelt deine Daten ankommen. Beispiel: User sendet zwei "hi"-Kommandos hintereinander: Sowohl sechs getrennte 1-Byte-Pakete mit "h","i","\n","h","i","\n" als auch ein großes Paket mit "hi\nhi\n" oder auch Mitteldinger wie "h","i\nh","i\n" sind "legal" und müssen von deinem Program korrekt empfangen und bearbeitet werden können. Pseudo-Code:
1 | std::string befehl; |
2 | while (ok) { |
3 | char buffer[2048]; |
4 | int bytesRec = recv(conn, buffer, sizeof(buffer), 0); |
5 | for (int i=0; i<bytesRec; ++i) { |
6 | char ch=buffer[i]; |
7 | if (ch==10) { // Linefeed |
8 | execute_command(strip_whitespace(befehl)); |
9 | befehl=""; |
10 | } else if (ch==10) { // CR, ignore |
11 | } else { |
12 | befehl += ch; // append to buffer. |
13 | }
|
14 | }
|
15 | }
|
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.