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.