www.mikrocontroller.net

Forum: PC-Programmierung [C++] Telnet Server


Autor: Lukas M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Andi ... (xaos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gib dir doch am server  einfach mal die rohdaten aus die du 
empfängst..der zeielnumbruch ist evtl anderst..

Autor: mar IO (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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???).

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was ist denn dein Zeilenende zeichen?

Autor: Lukas M. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Lukas M. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Sry das war jetzt die header datei..

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
r: 0x48
r: 0x69
r: 0x0a
w: 0x47
w: 0xfc
w: 0x6c
w: 0x74
w: 0x69
w: 0x67
...
w: 0x0a
Evtl. noch mit Zeitstempel.

Diese Ausgabe würde vermutlich die Lösung bringen.

Ansonsten halt ein vollständiger Quelltext.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: AVR-Verwender (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Lukas M. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: AVR-Verwender (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das hier:
      //Empfangen und Ausgeben
      int BytesRec = recv(conn, Buffer, sizeof(Buffer), 0);
      Buffer[BytesRec] = 0;
      cout << "Client:" << Buffer << endl;

      //Befehle erkennen
      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.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
AVR-Verwender schrieb im Beitrag #1894685:
> das hier:
>
>       //Empfangen und Ausgeben
>       int BytesRec = recv(conn, Buffer, sizeof(Buffer), 0);
>       Buffer[BytesRec] = 0;
>       cout << "Client:" << Buffer << endl;
> 
>       //Befehle erkennen
>       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.

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
  *hi*
  lauten

  steht auf dem Schirm
  *
  hi*
  dann war da ein \n vor dem hi

  steht dort
  *hi
  *
  dann war das \n nach dem hi

  steht dort
  *
  hi
  *
  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

  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.

Autor: DirkB (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Lukas M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja es ist in der Tat so, dass nach dem "Hi" noch ein Zeilen umbruch kam.

Autor: Lukas M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie kann ich denn den Zeilen umbruch löschen? mit
Befehl = Befehl.substr(0, Befehl.length()-2);
komm ich zu keinem Ergebniss

Liebe Grüße

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
std::string befehl;
while (ok) {
  char buffer[2048];
  int bytesRec = recv(conn, buffer, sizeof(buffer), 0);
  for (int i=0; i<bytesRec; ++i) {
     char ch=buffer[i];
     if (ch==10) { // Linefeed
        execute_command(strip_whitespace(befehl));
        befehl="";
     } else if (ch==10) { // CR, ignore
     } else {
        befehl += ch; // append to buffer. 
     }
  }
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.