Forum: PC-Programmierung Telnet-Client basteln


von Joachim .. (joachim_01)


Angehängte Dateien:

Lesenswert?

Als halbwegs leidlicher C-, aber ziemlich ahnungsloser C++ Programmierer 
dingse ich gerade an einem einfachen Telnet-Client herum.
Nach dem Connect schickt der Server sofort eine Begrüßung zurück - 
leider ist aber davor und danach ne Menge Müll dabei. Wo liegt der/die 
Fehler?
1
void main ()
2
{
3
4
  string confirm;
5
  string strmessage;
6
  char message[200];
7
8
  long answer;
9
  WSAData wsaData;
10
  WORD DLLVersion;
11
  DLLVersion = MAKEWORD(2,1);
12
  answer = WSAStartup(DLLVersion, &wsaData);
13
  SOCKADDR_IN addr;
14
  int addrlen = sizeof(addr);
15
  SOCKET sConnect;
16
  sConnect = socket(AF_INET, SOCK_STREAM, NULL);
17
  addr.sin_addr.s_addr = inet_addr("192.168.2.112");
18
  addr.sin_family = AF_INET;
19
  addr.sin_port = htons(5024);
20
21
  cout << "connecting remote telnet server..." << endl;
22
23
  connect (sConnect, (SOCKADDR*)&addr, sizeof(addr));  
24
  Sleep(10);
25
  answer = recv(sConnect, message, sizeof(message), NULL);
26
  strmessage = message;
27
  cout << strmessage << endl;
28
  
29
  getchar();
30
31
}

von Klaus (Gast)


Lesenswert?

mal hier schauen:

Das Kernprotokoll wird in den IETF-Dokumenten RFC 854 und RFC 855 (STD 
8) beschrieben. STD 8 beschreibt einige grundsätzliche Arbeitsweisen des 
Protokolls und Erweiterungsmöglichkeiten.

MfG Klaus

von Joachim .. (joachim_01)


Lesenswert?

>Das Kernprotokoll wird in den IETF-Dokumenten RFC 854 und RFC 855 (STD
>8) beschrieben.
Hmm. Ich bin nicht sicher ob das mein Problem löst. Funktionieren tut's 
ja. Ich hab eben mal von message[200] alle chars mit '\0' formatiert, 
danach ging gar nix mehr. Sieht so aus als ob sich C und VC++ stark 
unterscheiden und Speicher unterschiedlich gehandhabt und verwaltet 
wird.

von Klaus (Gast)


Lesenswert?

Joachim ... schrieb:
> Funktionieren tut's ja.

Das sehe ich ganz anders. Das du ab und an mal lesbare ASCII Zeichen 
findest, heißt nicht, das auch nur irgendein Stück des Telnet Protokols 
funktioniert. Lesen bildet !

MfG Klaus

von Εrnst B. (ernst)


Lesenswert?

Von der fehlenden Telnet-Implementierung mal abgesehen:

der Rückgabewert von recv ist die Anzahl der gelesenen Zeichen. Dem 
String-Construktor musst du die mitgeben.

also sowas wie

std::string received_text(message,answer);
...
std::cout << received_text;

von Joachim .. (joachim_01)


Lesenswert?

>Von der fehlenden Telnet-Implementierung mal abgesehen:
Was bedeutet das? Ich hab noch nen Teil in ner h.Datei stehen:

#pragma once
#pragma comment(lib, "Ws2_32.lib")

#include <sdkddkver.h>
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>


Oder meinst du etwas anderes?

von Εrnst B. (ernst)


Lesenswert?

Joachim ... schrieb:
> Oder meinst du etwas anderes?

Telnet ist mehr als "TCP auf den Bildschirm bringen", da ist ein 
Protokoll mit Handshake zwischen Client&Server mit dabei, dieses 
implementierst du nicht.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Joachim ... schrieb:
> Ich hab eben mal von message[200] alle chars mit '\0' formatiert,
> danach ging gar nix mehr. Sieht so aus als ob sich C und VC++ stark
> unterscheiden und Speicher unterschiedlich gehandhabt und verwaltet
> wird.

Nein, da gibt es keinen Unterschied, sofern Du mit "VC++" nicht die auf 
dem .Net-Geraffel aufsetzende Microsoft-Perversion namens "C++/CLI" bzw. 
"Managed C++" meinst.

Wie hast Du "alle chars mit '\0' formatiert"?

Hast Du Dir mal den Rückgabewert von recv näher angesehen? Was mag der 
für eine Bedeutung haben?

von Joachim .. (joachim_01)


Lesenswert?

Wie hast Du "alle chars mit '\0' formatiert"?
char message[200] funktioniert jetzt vernünftig.

Aber vermute ich werde doch erst nen paar Grundlagen in Erfahrung 
bringen müssen.
Hab eben noch mal nen send/recv Austausch mit Steuerzeichen für den 
Multimeter an den Server probiert, da gabs dann ne Meldung daß das Array 
message[] korrupt wäre...

Hm.

Schönen dank erstmal.

von DirkB (Gast)


Lesenswert?

Telnet kann man auch in C programmieren.
Denn Telnet ist älter als C++.

von Sebastian (Gast)


Lesenswert?

1. Vor strmessage = message sollte message mit '\0' enden. Z.b. 
message[answer] = 0;

2. Nach dem Verbindungsaufbau werden bei Telnet zwischen Client und 
Server diverse Optionen ausgehandelt. Dazu senden beide Seiten WILL, 
WONT, DO, DONT fuer die verschiedenen Optionen bis zur Einigung. Lies 
das noch mal in http://www.faqs.org/rfcs/rfc854.html und 
http://www.faqs.org/rfcs/rfc855.html nach.

LG, Sebastian

von Netz (Gast)


Lesenswert?

ssh kann auch wunderbar remote commandos ausführen.

z.b. "ssh kiste ls" führt ein ls auf "kiste" aus.

Dazu benutzt man Keys ohne passphrase und begrenzt die commandos in der 
authorizedkeys.

Fertig ist der Lack!

von Joachim .. (joachim_01)


Lesenswert?

>Dazu benutzt man Keys ohne passphrase und begrenzt die commandos in der
>authorizedkeys.
Nicht zielführend.

>Nach dem Verbindungsaufbau werden bei Telnet zwischen Client und
>Server diverse Optionen ausgehandelt.
Aaaaaha! Daher auch die Sonderzeichen vor der eigentlichen textuellen 
Begrüßung. Danke!
Dann müßte ich die wohl bloß ausblenden?


Wie auch immer. Ich hab den Code (stammt aus nem Tutorial) jetzt am 
laufen, allerdings werden nach ein paar Minuten keine Daten mehr an den 
Server im Multimeter übertragen... als ob es zu einem Pufferüberlauf 
kommt. Muß ich irgendwo zwischendurch Daten abholen oder so ne Art 
Quittierung senden? Mülle ich den Socket zu? Wie gesagt, ich hab mitm 
schreiben von Netzwerkanwendungen keine und mit VC++ nur sehr wenig 
Erfahrung.


1
#pragma once
2
#pragma comment(lib, "Ws2_32.lib")
3
4
5
#include <sdkddkver.h>
6
#include <WinSock2.h>
7
#include <Windows.h>
8
#include <iostream>
9
#include <string>
10
//#include <time.h>
11
12
using namespace std;
13
14
15
16
17
void main ()
18
{
19
  string confirm;
20
  string strmessage;
21
  char message[200];
22
  //for (int i = 0; i< 201; i++) message[i] = 0;
23
  long answer;
24
  WSAData wsaData;
25
  WORD DLLVersion;
26
  DLLVersion = MAKEWORD(2,1);
27
  answer = WSAStartup(DLLVersion, &wsaData);
28
  SOCKADDR_IN addr;
29
  int addrlen = sizeof(addr);
30
  SOCKET sConnect;
31
  sConnect = socket(AF_INET, SOCK_STREAM, NULL);
32
  addr.sin_addr.s_addr = inet_addr("192.168.2.112");
33
  addr.sin_family = AF_INET;
34
  addr.sin_port = htons(5024);
35
36
  cout << "connecting remote telnet server..." << endl;
37
    
38
  connect (sConnect, (SOCKADDR*)&addr, sizeof(addr));  
39
  Sleep(10);    //notwendig?
40
  int i;
41
  for (i = 0; i<sizeof(message); i++) message[i] = 0;
42
  answer = recv(sConnect, message, sizeof(message), NULL);   // Welcome...
43
  strmessage = message;
44
  cout << strmessage << endl;
45
  
46
  Sleep(50);
47
  answer = send(sConnect, "*IDN?\r", 7, NULL);
48
  Sleep(10);
49
50
  for (i = 0; i< 201; i++) message[i] = 0;
51
  answer = recv(sConnect, message, sizeof(message), NULL);
52
  strmessage = message;
53
  cout << strmessage << endl;
54
    Sleep(100);
55
  char* pmessage;
56
    
57
  char message1[40];
58
//  pmessage = &message1[0];
59
  int sleeptime = 50;
60
  int counter = 0;
61
62
  pmessage = "DISP:WIND2:TEXT \'1234567890         \'\r";
63
64
   while (1) 
65
   {
66
  //for (i = 0; i<sizeof(message1); i++) message1[i] = 0;
67
  //pmessage = "DISP:WIND2:TEXT \'1234567890AB\'\r";//duch das zweite Display durchscrollen
68
  
69
     
70
71
  cout << counter++ << endl;
72
  //  pmessage = "DISP:WIND2:TEXT \'1234567890         \'\r";
73
  answer = send(sConnect, "DISP:WIND2:TEXT \'1234567890         \'\r", strlen(pmessage), NULL);
74
  Sleep(sleeptime);
75
  //  pmessage = "DISP:WIND2:TEXT \'234567890          \'\r";  
76
  answer = send(sConnect, "DISP:WIND2:TEXT \'234567890          \'\r", strlen(pmessage), NULL);
77
  Sleep(sleeptime);
78
  }
79
  getchar();
80
81
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Auweia:
1
  char message[200];
2
3
  for (i = 0; i< 201; i++) message[i] = 0;


Na, was geht da wohl schief?

Besorg Dir ein C-Buch. Empfehlung: Brian Kernighan & Dennis Ritchie, 
"Programmieren in C", Zweite Ausgabe, Hanser-Verlag.

Da das, was Du da machst, sowieso kein C++ ist (außer dem Nutzen von 
cout), passt das; und das, was Du da falsch machst, ist auch in C++ 
falsch.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Rufus Τ. Firefly schrieb:
> was Du da falsch machst, ist auch in C++
> falsch.

Nicht nur in C++ ;-)
Die ganzen Probleme entstehen hier meiner Meinung nach einfach weil 
unstrukturiert vorgegangen wird. Und an den symptomen herumgedocktert 
wird.

Joachim ... schrieb:
> Aaaaaha! Daher auch die Sonderzeichen vor der eigentlichen textuellen
> Begrüßung. Danke!
> Dann müßte ich die wohl bloß ausblenden?

Schau doch einfach mal in das Dokument, lese (und beantworte) die 
Anfragen und gib nicht alles stur aus. Was ist überhaupt dein Ziel? 
Telnet-Clients gibt es ja wohl wie Sand am Meer (auch skripting fähige).

von Joachim .. (joachim_01)


Lesenswert?

>Na, was geht da wohl schief?
;-)


>Das sehe ich ganz anders. Das du ab und an mal lesbare ASCII Zeichen
>findest, heißt nicht, das auch nur irgendein Stück des Telnet Protokols
>funktioniert. Lesen bildet !
Ok, ich seh's ein. Mein Client scheint da ein paar Bedingungen zu 
übergehen. Auch ist das Fehlerverhalten nicht immer gleich. Werd' mich 
wohl tiefer einlesen müssen bevor ich den nächsten Versuch starte...

von DirkB (Gast)


Lesenswert?

Warum nimmst du denn den telnet Port?
Das Gerät (Agilent 34410A aus deinem Bild) hat auch ganz normale Sockets 
ohne großes Protokoll.
Nachdem was ich in 10 Minuten im Netz gelesen habe, sind das die Ports 
5025 oder 5042.
Das kann man aber auch sicher einstellen.

Zum Probieren kannst du auch Putty nehmen. Das kennt Telnet und auch 
einen Raw-Mode.

Oder mit netcat von der Kommandozeile zum ausprobieren.

von Joachim .. (joachim_01)


Lesenswert?

Mmmhhh ja, das mit 5025 hab ich probiert, aber da stellt sich der Socket 
im Moment noch tot. Mit Putty geht's.

>hat auch ganz normale Sockets
>ohne großes Protokoll.
Sagen wir mal so: mit dem obigen paar Zeilen funktioniert's. Ich hab 
auch nen Source von Agilent in dem der Datenaustausch rein funktional 
gesehen nach dem gleichen Arme-Leute-Schema abläuft. Also nix groß 
Protokoll, nix DO, DONT, WILL und WONT... und so - allerdings mit Port 
5025 statt 5024. Es funktioniert unter Putty sogar(?) der Raw-Mode.


Ich habe jetzt auch meinen Fehler gefunden. Bei jeder Anweisung sendet 
der Server die ASCII-Kette "34410A>" zurück. Das geht natürlich nur so 
lange gut bis der Empfangspuffer voll ist... Ein Dummy-read hat das 
Problem gelöst.

von DirkB (Gast)


Lesenswert?

Joachim ... schrieb:
> Bei jeder Anweisung sendet
> der Server die ASCII-Kette "34410A>" zurück
Kommt das auch mit PUTTY ?
Im Raw-Modus (Port 5025) und/oder im Telnet-Modus (Port 5024)?

von Joachim .. (joachim_01)


Lesenswert?

>Kommt das auch mit PUTTY ?
>Im Raw-Modus (Port 5025) und/oder im Telnet-Modus (Port 5024)?
Ja, sowohl bei Putty und auf 5024 unabhängig vom Telnet-Client. Bei 
"Raw" weiß ich nimmer genau, denke aber schon. Auf 5025 kommt nur nen LF 
zurück.


Hab jetzt ne Verbindung auf 5024 seit fast drei Std am Laufen und 
schicke ununterbrochen alle paar zehntel Sekunden ne Anfrage. Funzt 
einwandfrei.

Falls es dich interessieren sollte was Agilent dazu vorschlägt:
http://www.staff.uni-bayreuth.de/~btp918/cmt2007/geraete/agilent_34410A_dmm/manual/SCPI_Sockets.pdf
Wie gesagt, ist inhaltlich das Gleiche wie das was ich in nem Tut 
gefunden hab.

von DirkB (Gast)


Lesenswert?

Dann wird das "34410A>" das Prompt sein.

Zur Steuerung von einem Programm aus ist der reine Socket (5025) 
wesentlich besser geeignet.
Vor allem weil das Übertragungsende durch ein \r\n angezeigt wird.
Da brauchst du auch nicht mehr die ganzen Sleep in deinem Code.

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.