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


von Lukas M. (Gast)


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

von TestX .. (xaos)


Lesenswert?

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

von mar IO (Gast)


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???).

von Peter (Gast)


Lesenswert?

was ist denn dein Zeilenende zeichen?

von Lukas M. (Gast)


Angehängte Dateien:

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.

von Lukas M. (Gast)


Angehängte Dateien:

Lesenswert?

Sry das war jetzt die header datei..

von Klaus W. (mfgkw)


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:
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.

von Karl H. (kbuchegg)


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.

von AVR-Verwender (Gast)


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)

von Yalu X. (yalu) (Moderator)


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.

von Lukas M. (Gast)


Angehängte Dateien:

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

von AVR-Verwender (Gast)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von DirkB (Gast)


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.

von Lukas M. (Gast)


Lesenswert?

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

von Lukas M. (Gast)


Lesenswert?

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

von Klaus W. (mfgkw)


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.

von Εrnst B. (ernst)


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:
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
Noch kein Account? Hier anmelden.