Strings an ein Device senden wie mit Putty

parthagas

Grünschnabel
Hallo,

ich bin noch ganz frisch mit der Visual C++ und Netzwerkprogrammierung. Deshalb muss ich jetzt hier um Rat fragen.
Also ich habe ein Automationsgerät, welches über Netzwerk strings abfrägt and dann Aufgaben erledigt.
Also zB Gerät erhält String "Do1" dann macht es ein bestimmtes Programm auf.
Wenn ich eine Verbindung über Putty aufmache mit Telnet oder Raw, die Ip und den Port eingebe, dann funktioniert das auf wunderbar.
--->ich gebe "Do1" ein --->Programm startet

Jetzt wollte ich mir die ganze Sache selbst Programmieren und bin dabei über die Beispiele von http://www.c-worker.ch/tuts.php gestoßen.
Diese funktionieren auch mit Server+ Client.
Wenn ich das Clientprogramm allein laufen lasse und an mein Gerät connecte, kann iach zwar senden, aber es passiert nichts.
hier der Code des Clientbeispiels:
C++:
#pragma comment(lib, "Ws2_32.lib") 

#include "stdafx.h"

#include <windows.h>
#include <stdio.h> 


//Prototypen
int startWinsock(void);
long getAddrFromString(char* hostnameOrIp, SOCKADDR_IN* addr);

int main(int argc, char** argv)
{
  long rc;
  SOCKET s;
  SOCKADDR_IN addr;
  char buf[256];

  if(argc<2)
  {
    printf("Usage: sock <hostname oder ip des servers>\n");
    return 1;
  }


  // Winsock starten
  rc=startWinsock();
  if(rc!=0)
  {
    printf("Fehler: startWinsock, fehler code: %d\n",rc);
    return 1;
  }
  else
  {
    printf("Winsock gestartet!\n");
  }

  // Socket erstellen
  s=socket(AF_INET,SOCK_STREAM,0);
  if(s==INVALID_SOCKET)
  {
    printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("Socket erstellt!\n");
  }

  // Verbinden
  memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten
  addr.sin_family=AF_INET;
  addr.sin_port=htons(32001); // wir verwenden mal port 12345
  rc=getAddrFromString(argv[1],&addr);
  if(rc==SOCKET_ERROR)
  {
    printf("IP für %s konnte nicht aufgeloest werden\n", argv[1]);
    return 1;
  }
  else
  {
    printf("IP aufgeloest!\n");
  }


  rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
  if(rc==SOCKET_ERROR)
  {
    printf("Fehler: connect gescheitert, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("Verbunden mit 127.0.0.1..\n");
  }


  // Daten austauschen
  while(rc!=SOCKET_ERROR)
  {
    printf("\nZeichenfolge eingeben [max 256]: ");
    gets(buf);
    send(s,buf,strlen(buf),0);
   // rc=recv(s,buf,256,0);
  //  if(rc==0)
    {
    //  printf("Server hat die Verbindung getrennt..\n");
     // break;
    }
    if(rc==SOCKET_ERROR)
    {
      printf("Fehler: recv, fehler code: %d\n",WSAGetLastError());
      break;
    }
    buf[rc]='\0';
    printf("\nServer antwortet: %s\n",buf);
  }
  closesocket(s);
  WSACleanup();
  return 0;
}

int startWinsock(void)
{
  WSADATA wsa;
  return WSAStartup(MAKEWORD(2,0),&wsa);
}


long getAddrFromString(char* hostnameOrIp, SOCKADDR_IN* addr)

{
  long rc;
  unsigned long ip;
  HOSTENT* he;


  /* Parameter prüfen */
  if(hostnameOrIp==NULL || addr==NULL)
    return SOCKET_ERROR;


  /* eine IP in hostnameOrIp ? */
  ip=inet_addr(hostnameOrIp);

  /* bei einem fehler liefert inet_addr den Rückgabewert INADDR_NONE */
  if(ip!=INADDR_NONE)
  {
    addr->sin_addr.s_addr=ip;
    return 0;
  }
  else
  {
    /* Hostname in hostnameOrIp auflösen */
    he=gethostbyname(hostnameOrIp);
    if(he==NULL)
    {
      return SOCKET_ERROR;
    }
    else
    {
      /*die 4 Bytes der IP von he nach addr kopieren */
      memcpy(&(addr->sin_addr),he->h_addr_list[0],4);
    }
    return 0;

  }
}

Könntet Ihr mir bitte ein paar Tipps geben warum das nicht funktioniert, und wo ich mich weiter einlesen kann?

Mfg
Chris
 
Zuletzt bearbeitet von einem Moderator:
Hi.

Bitte nutze die Code-Tags für deinen Code.

Ich vermute mal du müßtest den Befehl mit einem Zeilenendezeichen abschließen.

Die Funktion gets liest eine Zeile bis zum \n ein, verwirft das \n aber. D.h. du müßtest noch ein \n an den String dranbasteln und dementsprechend auch übertragen.

Gruß
 
Danke für die schnelle Antwort!

Macht Putty denn eine Terminierung? Die Strings sende ich dort ohne.
Ich habs jetzt mit \n , \r\n und \0 probiert, aber da passiert einfach nichts.
Was macht denn Putty so viel anders?

Gibt es vielleicht ein anderes Codebeispiel, bei dem man an einen Netzwerkpartner einen String sendet?
 
Soweit ich weiss wird bei Telnet jedes Zeichen sofort nach der Eingabe zum verbundenen Endgerät geschickt. Wenn dein Client nun jedoch einen vollständigen Befehl erwartet und alle davor eingegangenen Daten verwirft kann dein Client nicht mehr als 1-zeichenlange Befehle interpretieren. Schreib einfach alle Daten die du bisher erhalten hast in einen Buffer und werte die Übertragung erst mit Übertragung von \r\n aus.
 
So, ich habe jetzt mit wireshark verglichen was passiert wenn ich "test" sende:

Putty sendet:
0000 00 50 c2 bf d0 20 8c 73 6e ab 1c 58 08 00 45 00 .P... .s n..X..E.
0010 00 2c 05 7b 40 00 80 06 00 00 c0 a8 01 81 c0 a8 .,.{@... ........
0020 01 c9 c6 e9 7d 01 bb 3e 0e 09 1c 3f 69 21 50 18 ....}..> ...?i!P.
0030 40 e8 84 b9 00 00 74 65 73 74 @.....te st

0000 00 50 c2 bf d0 20 8c 73 6e ab 1c 58 08 00 45 00 .P... .s n..X..E.
0010 00 2a 05 77 40 00 80 06 00 00 c0 a8 01 81 c0 a8 .*.w@... ........
0020 01 c9 c6 e9 7d 01 bb 3e 0e 07 1c 3f 69 21 50 18 ....}..> ...?i!P.
0030 40 e8 84 b7 00 00 0d 0a @.......

Ich sende nur:

0000 00 50 c2 bf d0 20 8c 73 6e ab 1c 58 08 00 45 00 .P... .s n..X..E.
0010 00 2c 05 38 40 00 80 06 00 00 c0 a8 01 81 c0 a8 .,.8@... ........
0020 01 c9 c6 e8 7d 01 32 fc a3 04 5e fc 19 72 50 18 ....}.2. ..^..rP.
0030 40 e8 84 b9 00 00 74 65 73 74 @.....te st


Ich schätze mal das zweite, leere Packet von Putty ist die Terminierung? Das Problem ist, wenn ich \n oder \0 eingebe sedet er es einfach mit, also zb @.....te st\n

Hier ist nochmal ein Codeausschnitt:
Code:
long rc;
  SOCKET s;
  SOCKADDR_IN addr;
  char buf[256];

  if(argc<2)
  {
    printf("Usage: sock <hostname oder ip des servers>\n");
    return 1;
  }


  // Winsock starten
  rc=startWinsock();
  if(rc!=0)
  {
    printf("Fehler: startWinsock, fehler code: %d\n",rc);
    return 1;
  }
  else
  {
    printf("Winsock gestartet!\n");
  }

  // Socket erstellen
  s=socket(AF_INET,SOCK_STREAM,0);
  if(s==INVALID_SOCKET)
  {
    printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("Socket erstellt!\n");
  }

  // Verbinden
  memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten
  addr.sin_family=AF_INET;
  addr.sin_port=htons(12345); // wir verwenden mal port 12345
  rc=getAddrFromString(argv[1],&addr);
  if(rc==SOCKET_ERROR)
  {
    printf("IP für %s konnte nicht aufgeloest werden\n", argv[1]);
    return 1;
  }
  else
  {
    printf("IP aufgeloest!\n");
  }


  rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
  if(rc==SOCKET_ERROR)
  {
    printf("Fehler: connect gescheitert, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("Verbunden mit 192.168.1.1\n");
  }


  // Daten austauschen
  while(rc!=SOCKET_ERROR)
  {
    printf("\nZeichenfolge eingeben [max 256]: ");
    gets(buf);
    send(s,buf,(strlen(buf)+1),0);
  }
  closesocket(s);
  WSACleanup();
  return 0;
}

Wie kann ich die Eingabe Terminieren, ohne dass es gesendet wird?

Grüße
Chris
 
Hallo,
wie du schon richtig erkannt hast, sendet putty in dem zweiten Paket Terminierungszeichen.
Am Ende des ersten Paketes hast du deine Nutznachricht (74 65 73 74 = test) und in dem zweiten Paket \0 \0 \r \n (0a = ascii-10 und 0d = ascii-13)

versuch doch mal Folgendes:
C++:
 while(rc!=SOCKET_ERROR)
  {
    printf("\nZeichenfolge eingeben [max 256]: ");
    gets(buf);
    send(s,buf,(strlen(buf)+1),0);
    buf[0] = '\r';
    buf[1] = '\n';
    Sleep(300);
    send(s,buf, 2, 0);
  }


Außerdem: wenn du \n in der Konsole eingibst, so wird das als Text - ein Backslash und ein n interpretiert und nicht als Steuerzeichen.

Gruß,
kickerxy
 
Zuletzt bearbeitet:
Hi kickerxy. Erstmal danke, die Terminierung scheint nun zu funktionieren.
Jetzt sehen beide gleich aus (Putty und meins).

Trotzdem passiert bei meinem Programm noch nichts während bei Putty alles geht.

Habe mir beide nochmal in wireshark angeschaut und gesehen, dass die Timings unterschiedlich sind.
Bei Putty folgen beide Pakete direkt hintereinander mit Seq. 22 und 23. Der Zeitabstand ist ca. 40Microsekunden. Erst dann kommt das ACK von dem Gerät (zu dem ich verbinden will).

Bei meiner Dosanwendung sind ein paar Millisekunden Abstand und das ACK kommt schon vor dem Paket mit der Terminierung. Die Seq. im wireshark hat einen großen Abstand.

Bedeutet das nun, dass es zu langsam sendet? Die Sleep(300) hab ich bereits auskommentiert, trotzdem noch das selbe.
Wie kann ich das zweite Paket sofort nach dem ersten senden?

Oder bin ich hier komplett auf dem Holzweg und es liegt an etwas ganz anderem...

MFG
 
Bei dem Code von kickerxy wird zwischen test und dem Zeilentrenne
noch ein \0 gesendet, das sollte weg.

Also da, wo zu strlen 1 addiert wird, das +1 weg.
 
hi sheel

Das +1 habe ich bereits eintfernt. Der Code sieht nun so aus:

Code:
while(rc!=SOCKET_ERROR)
  {
    printf("\nZeichenfolge eingeben [max 256]: ");
    gets(buf);
    send(s,buf,strlen(buf),0);
    buf[0] = '\r';
    buf[1] = '\n';
    send(s,buf, 2, 0);
  }

Trotzdem kommt das ACK vom Zielobjekt bereits nach dem 1 Paket (nach dem 2 auch nochmal) und der Zeitabstand ist viel größer.
 
Zurück