3. pararmeter von recv angeben



  • Hallo, ich habe (mit Hilfe 🙂 eine Server Client Anwendung geschrieben, wobei
    unterschiedliche "Nachrichten" verschickt werden können. Es gibt ein
    struct "Nachricht" der nur den NachrichtenTyp speichern kann und 2 weitere Nachríchten, die Nutzinformationen enthalten und von "Nachricht" erben.

    Nun muß ich bei recv( , , ,) im 3. pararmeter angeben, wieviel Daten im meine nachricht übertragen werden sollen. Nun habe ich das problem, dass ich ja erst bestimmen kann wie groß die Nachricht tatsächlich ist, wenn ich sie geladen habe. was muß ich also dort eintragen?

    Ich Poste mal den Server und den Client. Aber das Problem liegt zur Zeit nur beim Client, da nur er Daten vom Typ nachricht empfängt.

    Server:

    #include <winsock2.h>
    #include <windows.h>
    #include <stdio.h>
    
    struct Nachricht {					//Eine allgemeine nachricht, von der jede Andere erbt
    	int MsgType;  
    	Nachricht():MsgType(0){};
    }
    
    struct NachrichtTyp1: Nachricht 
    { 
    
       int x; 
       int y; 
    
      NachrichtTyp1(int x_, int y_)  { x = x_; y = y_;MsgType=1;}; 
      NachrichtTyp1()  {}; 
    }; 
    
    struct NachrichtTyp2: Nachricht 
    { 
    
      float x; 
      float y; 
      float z;
    
      NachrichtTyp2(float x_, float y_,float z_)  { x = x_; y = y_;z=z_;MsgType=2;}; 
       NachrichtTyp2()  {}; 
    }; 
    
    //////////////SERVER/////////////////
    int main()
    {
    
      long rc;
      SOCKET acceptSocket;
      SOCKET connectedSocket;
      SOCKADDR_IN addr;
      char buf[256];
    
      // Winsock starten
      rc=startWinsock();
    
      // Socket erstellen
      acceptSocket=socket(AF_INET,SOCK_STREAM,0);
    
      // Socket binden
      memset(&addr,0,sizeof(SOCKADDR_IN));
      addr.sin_family=AF_INET;
      addr.sin_port=htons(12345);
      addr.sin_addr.s_addr=ADDR_ANY;
      rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
    
      // In den listen Modus
      rc=listen(acceptSocket,10);
    
      // Verbindung annehmen
      connectedSocket=accept(acceptSocket,NULL,NULL);
    
      // Daten austauschen
      while(rc!=SOCKET_ERROR)
      {
    
    	// Diese 3 Zeilen sind eigentlich unnötig und geben nur das gesenete vom Client aus
        rc=recv(connectedSocket,buf,256,0);
        buf[rc]='\0';
        printf("Client sendet: %s\n",buf);
    
    	NachrichtTyp2 *i = new NachrichtTyp2(8,2,5);
    	rc=send(connectedSocket,(const char*)i, sizeof(NachrichtTyp2),0); 
    	delete (i);
    
      }
      closesocket(acceptSocket);
      closesocket(connectedSocket);
      WSACleanup();
      return 0;
    }
    
    int startWinsock(void)
    {
      WSADATA wsa;
      return WSAStartup(MAKEWORD(2,0),&wsa);
    }
    

    Client:

    #include <winsock2.h>
    #include <windows.h>
    #include <stdio.h>
    
    //Prototypen
    int startWinsock(void);
    
    struct Nachricht {					//Eine allgemeine nachricht, von der jede Andere erbt
    	int MsgType;  
    	Nachricht():MsgType(0){};
    };
    
    struct NachrichtTyp1: Nachricht		//Nachricht Typ 1, erbet von Nachricht
    { 
    
       int x; 
       int y; 
    
       NachrichtTyp1(int x_, int y_)  { x = x_; y = y_;MsgType=1;}; 
       NachrichtTyp1()  {}; 
    }; 
    
    struct NachrichtTyp2: Nachricht		//Nachricht Typ 2, erbet von Nachricht
    { 
    
      float x; 
      float y; 
      float z;
    
       NachrichtTyp2(float x_, float y_,float z_)  { x = x_; y = y_;z = z_ ;MsgType=2;}; 
       NachrichtTyp2()  {}; 
    }; 
    
    ////////////Client
    
    int main()
    {
      long rc;
      SOCKET s;
      SOCKADDR_IN addr;
      char buf[256];
    
      // Winsock starten
      rc=startWinsock();
    
      // Socket erstellen
      s=socket(AF_INET,SOCK_STREAM,0);
    
      // 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
      addr.sin_addr.s_addr=inet_addr("127.0.0.1"); // zielrechner ist unser eigener
    
      rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
    
      // Daten austauschen
      while(rc!=SOCKET_ERROR)
      {
    
        gets(buf);  // nur um auf eine Eingabe zu warten...
        send(s,buf,strlen(buf),0); //Server sendet eine Nachricht vom Typ NachrichtTyp1 oder NachrichtTyp2 wenn er irgentetwas empängt.
    
    	Nachricht*i = new Nachricht(); 
    	int Was_muss_hier_stehen=100000;				///Welchen Wert muß ich als 3. Pararmeter angeben?
    	recv (s,( char*)i,Was_muss_hier_stehen,0);
    
    	if (i->MsgType==1) {
    	NachrichtTyp1 *info=(NachrichtTyp1*)i;
    	printf( "%d\n", info->x ); 
        printf( "%d\n", info->y );
    	printf( "%d\n", info->MsgType);
    	}
    
    	if (i->MsgType==2) {
    	NachrichtTyp2 *info=(NachrichtTyp2*)i;
    	printf( "%f\n", info->x ); 
        printf( "%f\n", info->y );
    	printf( "%f\n", info->z );
    	printf( "%d\n", info->MsgType);
    	}
    
      }
    
      closesocket(s);
      WSACleanup();
      return 0;
    }
    
    int startWinsock(void)
    {
      WSADATA wsa;
      return WSAStartup(MAKEWORD(2,0),&wsa);
    }
    


  • Andreas XXL schrieb:

    Nun habe ich das problem, dass ich ja erst bestimmen kann wie groß die Nachricht tatsächlich ist, wenn ich sie geladen habe.

    Dann hast Du Dein Protokoll falsch definiert.
    Es gibt i.d.R. zwei verschiedene Ansätze:
    1. Du schickst zuerst mit, wie lange die folgenden Daten sind (also z.B. 4-byte, welche die Länge der nächsten Daten angibt)
    2. Du definierst ein eindeutiges Ende-Zeichen (z.B. CR); das setzt natürlich voraus, dass dieses Zeichen sonst niergens auftreten darf.



  • du musst auch den rückgabewert von recv überprüfen. du kannst nämlich auch nur 1 byte bekommen auch wenn du dort 12 angibst.



  • ß schrieb:

    du musst auch den rückgabewert von recv überprüfen. du kannst nämlich auch nur 1 byte bekommen auch wenn du dort 12 angibst.

    Ok. Der Rückabewert gibt doch an, wie viele Daten übertragen wurden.
    Aber was mache ich wenn es zu wenig sind? Dann sind doch zu wenig Daten in Mein "i" geladen worden. Wie kann ich denn dann die folgenden Daten in das Objekt i hinzufügen, so das nicht die die schon drin sind überschrieben werden?
    kann man irgendwie abfragen, wie viele daten im Empfangspuffer sind ohne diese dort rauszunehmen? Weil ich ja erst recv aufrufen möchte, wenn soviele Daten da sind, wie mein Objekt das ich "befüllen" möchte groß ist! Oder wie macht man das dann?

    recv (s,( char*)i,100,0);



  • Benutz halt ne Schleife bis du alles zusammenhast.

    Bei recv kannst du dann als Puffer i + bytesReceived und als Länge Strukturgroesse - bytesReceived angeben, dann wird auch nichts überschrieben.

    Warum legst du das Nachricht-Objekt überhaupt auf dem Heap an? Sieht ziemlich dämlich aus wenn du es danach sofort wieder freigibst.



  • Danke für die Hinweise!

    Ich habe jetzt die Nchrichten und das empfangen modifiziert und glaube, dass es jetzt so funktionieren müsste:

    #include <winsock2.h>
    #include <windows.h>
    #include <stdio.h>
    
    //Prototypen
    int startWinsock(void);
    
    struct Nachricht {//Eine allgemeine nachricht, von der jede Andere erbt
    	int groesse;
    	int MsgType;  
    	Nachricht():MsgType(0){groesse=sizeof(Nachricht);};
    };
    
    struct NachrichtTyp1: Nachricht		//Nachricht Typ 1
    { 
    
       int x; 
       int y; 
    
       NachrichtTyp1(int x_, int y_)  { x = x_; y = y_;MsgType=1;groesse=sizeof(NachrichtTyp1);}; 
       NachrichtTyp1()  {}; 
    }; 
    
    struct NachrichtTyp2: Nachricht		//Nachricht Typ 2 erbet von Nachricht
    { 
    
      float x; 
      float y; 
      float z;
    
       NachrichtTyp2(float x_, float y_,float z_)  { x = x_; y = y_;z = z_ ;MsgType=2;groesse=sizeof(NachrichtTyp2);}; 
       NachrichtTyp2()  {}; 
    }; 
    
    ////////////Client
    
    int main()
    {
      long rc;
      SOCKET s;
      SOCKADDR_IN addr;
      char buf[256];
    
      // 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
      addr.sin_addr.s_addr=inet_addr("127.0.0.1"); // zielrechner ist unser eigener
    
      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)
      {
    
        gets(buf);  // nur um auf eine Eingabe zu warten...
        send(s,buf,strlen(buf),0);
    	Nachricht*i = new Nachricht(); 
    
    /// Zuerst die ersten 4 Byte lesen, somit habe ich jetzt die groesse (steht dann in i unter i->groesse)
    int wert=0;
    while (wert<4) 
    {
    		wert=wert+recv (s,( char*)i+wert,4-wert,0);
    
    }
    wert=0;
    
    //Die restlichen Werte lesen (sind jetzt groesse-4)
    while (wert<i->groesse-4) 
    {
    		wert=wert+recv (s,( char*)i+wert+4,i->groesse-(wert+4),0);
    
    }
    
    	if (i->MsgType==1) {
    	NachrichtTyp1 *info=(NachrichtTyp1*)i;
    	printf( "%d\n", info->x ); 
        printf( "%d\n", info->y );
    	printf( "%d\n", info->MsgType);
    	}
    
    	if (i->MsgType==2) {
    	NachrichtTyp2 *info=(NachrichtTyp2*)i;
    	printf( "%d\n", info->groesse);
    	printf( "%f\n", info->x ); 
        printf( "%f\n", info->y );
    	printf( "%f\n", info->z );
    	printf( "%d\n", info->MsgType);
    	}
      }
    
      closesocket(s);
      WSACleanup();
      return 0;
    }
    
    int startWinsock(void)
    {
      WSADATA wsa;
      return WSAStartup(MAKEWORD(2,0),&wsa);
    }
    

    Sind da jetzt noch Fehler vorhanden?



  • Vehlerbehandlung wäre nicht schlecht.


Anmelden zum Antworten