Winsock
-
Weil ich die Größe vor den Empfangen der eigendlichen Nachricht abfragen muss, habe ich sie an den Anfang eines char* vorangestellt. Somit kann ich erst die Größe der zulesenden Bytes lesen und den buffer dann auslesen. Leider funktioniert das nicht, kann mir einer helfen?
hier der code:
int bytecounter = 0; char* recbyte = NULL; //Information der Größe auslesen if (recv (daMember[counter].Socket, (char*) &bytecounter, sizeof (int), 0) != sizeof (int)) { //Socketerror zurückliefern return SOCKET_ERROR; } else { recbyte = new char [bytecounter]; int n = recv (daMember[counter].Socket, recbyte, bytecounter, 0); char* probe = recbyte; } //UI- Struktur füllen memset (&userinformation, 0, sizeof (UI)); //erstes Byte (BOOLEAN) des Empfangsbuffers in registry kopieren memcpy (&userinformation[counter].registry, recbyte, sizeof (bool)); //für den Fall eines Gastzuganges if (userinformation[counter].registry == false) { userinformation[counter].nickname = new char [100]; //Nicknamen rauskopieren memcpy (&userinformation[counter].nickname, recbyte + sizeof (bool), bytecounter - sizeof (bool)); //userinformation[counter].nickname = "hallo"; cout << &userinformation[counter].nickname << endl; cout << userinformation[counter].nickname << endl; daMember[counter].myuser = new char [bytecounter]; memcpy (daMember[counter].myuser, userinformation[counter].nickname, bytecounter - sizeof (bool)); } //ansonsten weitere Daten rauskopieren else { }
kann mir einer helfen ? wäre sehr nett.
-
Passt besser nach WinAPI.
-
zunächst zu sagen, dass wieder mal n böser mischmasch aus c und c++ ist (malloc <-> new) entscheid dich für eins von beiden.
zähle hier mal n paar ungereimtheiten auf:- recv gibt einen int wert zurück, der > 0 bei einem fehler, und sonst die anzahl bytes die empfangen wurden, also ist das "!= sizeof (int)" total fehl am platz
- was soll dieser komische cast mit dem (char
&bytecounter? das kann hinten und vorne nicht funktionieren. recv erwartet einen char buffer. versuch mal in einen int wert den satz "Hallo Peter ich komme heute nicht vorbei" zu quetschen, viel erfolg!
- verwende einen großgenugen standardbuffer (1024 Byte wird häufig genommen) und vergiss nicht die NULL terminierung dessen! (buffer[recieved_bytes] = '\0')
- bin mir nicht sicher, ob es überhaupt eine methode gibt um an die größe des emfangenen heranzukommen, ohne es abzuholen
hoffe das hilft mal etwas
-
ioctlsocket sollte die Funktion sein, die du suchst. Schau mal im MSDN nach.
-
1. ich nutze immer new, malloc habe ich noch nie benutzt und steht auch in dem quellcode nicht
2. recv gibt bei einem Fehler einen Wert von < 0 zurück nicht >0. Ich frage in der Schleife ab, ob der int empfangen wurde, und das funktioniert auch einbandfrei.
3. ich caste zu char* weil recv einen char* verlangt. ausserdem kann in einem Buffer beliege daten stehen, bis dahin funktioniert das programm auch noch.
4. Ich brauche keine Standartgröße, weil ich die größe mitliefere und das funktioniert auch, beim zweiten aufruf von recv liegen die Probleme, da werden die daten nicht auf den buffer übertragen
-
zu 1) sry, meinte memcpy und memset, aber das kommt auf gleiche schiene
zu 2) sry, tippfehlergenerell, wenn du keine hilfe willst, sags, dann post ich einfach nix mehr
das problem ist meines erachtens, dass du ja den text auf einmal verschickst. wenn du jetzt nur einen teil abholst, verfällt der rest. wie man das umgehen kann, hm, kA. wenn du an dieser methode festhalten willst, splitte das paket doch in 2 teile auf: einmal den intwert schieben, dann den text.
wobei ich nicht versteh, wieso du nicht den normalen weg über einen buffer gehst. naja, jedem das seine
edit: Frank II's Tip is der richtige!
[ Dieser Beitrag wurde am 22.04.2003 um 23:13 Uhr von Korbinian editiert. ]
-
Danke, ich wollte dich nicht kritisieren, ich will nur nicht das wir aneinander vorbeireden, kann deine Hilfe sehr wohl gebrauchen. Zu dem Thema noch: es geht nicht um Nachrichten, es geht um die Informationen, die beim Einloggen an den Server geschickt werden müssen. Deshalb verschicke ich im wesentlichen eine Struktur, die ich in einem Buffer serialisiere. Der Buffer hat folgenden Aufbau:
int (die größe)+ die restlichen daten
ich gehe im moment von dem fall aus das nur ein gastzugang gesendet wird, für den fall wird nur ein bool (der entscheidet ob registrierung vorliegt oder nicht, welcher in dem fall immer false sein muss) und dem nicknamen. Um das auslesen dieser Informationen geht es.
cu Para
-
hat die struktur einen festen aufbau, ist das kein problem denk ich. mit fest meine ich, dass die größe nicht variiert, also z.b.:
struct User { bool registred; char username[10]; char passwd[10]; }; struct Command { int cmd_id; char cmd_value[50]; };
in diesem fall musst du nur die gesamtgröße der struktur wissen. wenn du also weist, dass du eine Instanz von 'User' schickst, dann weist du dass das bisschen mehr als 20 byte sind (hab jetz nicht genau gerechnet), entsprechend kannst du soviele bytes empfangen.
schwierig dabei wird allerdings folgendes: da send nur strings versendet, diese struktur (User) aber mindestens 2 binäre nullen enthält, wird das nicht funktionieren. evtl. geht da read und writeaber als tip: es ist meines erachtens geschickter, ein protokoll aufzubauen anstatt binäre daten umherzuschicken. der zeitaufwand ist ähnlich groß.
-
nein meine Struktur hat leider keine feste Größe, da sie durch char* geprägt wird und somit die Größe von der Länge der Zeichenketten abhängt. Deshalb serialisiere ich die Struktur ja auch in einen Buffer, denn wenn ich das nicht machen würde würde send zwar die Struktur senden, allerdings nicht die Zeichenketten, sondern die Anfangsadressen, auf die die Zeiger zeigen, und das ist ja völliger Quatsch.
die stuktur die letzendlich verschickt wird ist folgende
struct UI { char* nickname; char* keyword; bool registry; char* name; char* prename; char* street; int streetnumber; int birthday; int birthmonth; int birthyear; char* birthcity; char* motherlanguage; UI () { nickname = new char [100]; keyword = new char [100]; name = new char [200]; prename = new char [200]; street = new char [200]; birthcity = new char [100]; motherlanguage = new char [50]; } ~UI () { if (nickname != NULL) { delete [] nickname; } if (keyword != NULL) { delete [] keyword; } if (name != NULL) { delete [] name; } if (prename != NULL) { delete [] prename; } if (street != NULL) { delete [] street; } if (birthcity != NULL) { delete [] birthcity; } if (motherlanguage != NULL) { delete [] motherlanguage; } } };
Wie ich ein Protokoll entwickle weiss ich nicht. Aber das einzige Problem ist ja das ich recv zweimal aufrufen muss, beim ersten recv wird die größe ja perfekt gelesen die stimmt auch immer. beim zweiten recv bleibt allerdings der buffer leer sodass nur ein Nullbyte drinsteht.[code type="C++" tabs="4"]
-
das problem ist meines erachtens, dass du ja den text auf einmal verschickst. wenn du jetzt nur einen teil abholst, verfällt der rest
nö
schwierig dabei wird allerdings folgendes: da send nur strings versendet, diese struktur (User) aber mindestens 2 binäre nullen enthält, wird das nicht funktionieren
nö, send verschickt soviele Bytes aus dem angegebenen Buffer, wie angegeben wird
Zum Problem:
nickname = new char [100]; keyword = new char [100]; name = new char [200]; prename = new char [200]; street = new char [200]; birthcity = new char [100]; motherlanguage = new char [50];
Die größe ist doch konstant/bekannt? Du kannst also mit send( , &Struktur, sizeof(struct UI)); die ganze Struktur auf einmal senden und auch empfangen?
Warum bei dir allerdings nach dem ersten recv() nichts mehr ankommt ist eine gute Frage, wird es auch wirklich gesendet?
Tipp: Selbst wenn du weißt, dass z.B. 442B gesendet wurden heißt das noch lange nicht, dass du sie mit einem recv() alle abholen kannst, deshalb musst du recv solange aufrufen, bis du alle Bytes empfangen hast.
Außerdem muss das was du sendest nicht unbedingt ankommen, das soltest du ebenfalls im Protokoll berücksichtigen!
-
deine struktur hätteste auch leichter schreiben können, da du ja trotzdem fixe werte bei new hast.
struct UI { char nickname[100]; char keyword[100]; bool registry; char name[200]; char prename[200}; char street[200]; int streetnumber; int birthday; int birthmonth; int birthyear; char birthcity[100]; char motherlanguage[50]; };
und schon hat die struktur nen festen aufbau
nochmal: wenn du wissen willst, wieviele byte auf einem sockel bereit zur abholung liegen brauchst du (unter windows) die funktion ioctlsocket, die FrankII vorhingenannt hat. die liefert dir einen u_int, wieviele byte zur abholung bereit stehen.protokoll ist nichts anderes als ein festgelegter "handlungstrang" in der "konversation" client-server. dabei empfielhlt es sich, festgelegte befehle oder sequenzen durch kürzel kennzeichnet. z.B. "01" = alles OK, "XX" = fehler oder so ähnlich.
in deinem Fall würd ich etwa folgendes machen: ( C= client, S= server)
c -> s verbinden
s -> c: "00 Server bereit" // das praktische ist, du musst nur die ersten 2 chars auslesen, um herauszubekommen, was sinn des paketes ist. der text wird dann nur nach bedarf ausgewertet
c -> s: "10 Login"
s -> c: "01 OK"
c -> s: "05 Peter" // 05 steht z.b. für USERNAME
s -> c: "01 Received Peter"
c -> s: "06 geheim" // 06 steht z.b. für PASSWORT
s -> c: "01 Received password"
...
wenn du dann diese nachrichten mitprotokollierst, kann man auch schön bugtracking machen
-
was ist denn diese funktion, was macht sie und wie setzt man sie ein? ich habe in der msdn nachgeschaut, komme mit ihr aber nicht zurecht.
-
laut msdn kannst du dir damit die anzahl bytes die am sockel warten abholen. der parameter den du als cmd übergeben musst is F_ irgenwas (lies halt in der msdn)
so wie ich das verstandne hab, hast dann nach dem aufruf in dem u_int die anzahl wartender bytes stehen
-
ja ich kapier ja net was da steht also die funktion gibt doch 0 zurück wenn sie erflogreich ist und einen Fehlercode wenn was schiefgeht. und man kann mit der Funktion das Verhalten des Sockets beeinflussen soweit habe ich es verstanden mehr nicht. kann mir vielleicht einer die Funktion mal erklären?
-
Hi,
na ganz so schwer ist das doch nicht zu verstehen
(oder ist's die Sprache?)
int ioctlsocket( SOCKET s, long cmd, u_long* argp );
SOCEKT s ist der Handle auf deinen SOCKET, müsste also in deinem Fall daMember[counter].Socket sein.
long cmd => FIONREAD (in Winsock2.h definiert)
u_long* argp => Ein Zeiger auf eine Variable von type unsigned long in die das Ergebniss gespeichert wird, also die zu lesenden Bytes.
Fehler/Erfolg werden über den Returncode der Funktion signalisiert, wie Du ja schon richtig erkannt hast.
Der Aufruf sollte also ungefähr so aussehen. (nicht getestet)
ioctlsocket( daMember[counter].Socket, FIONREAD, &bytes_to_recv );
Hoffe es hat geholfen!
Ansonsten in der MSDN noch mal genau nachlesen.
http://msdn.microsoft.com/library/en-us/winsock/winsock/ioctlsocket_2.asp?frame=true
-
ja hat es, eine Frage hab ich aber noch. Wozu ist diese Funktion überhaupt gut? Also was bringt mir das?
-
Also was macht die funktion denn damit? die Syntax war mir ja schon klar, wird die funktion dazu benutzt die am socket wartenden Daten (die anzahl der bytes) zu bestimmen? In der msdn habe ich das so verstanden, dass ein Socket damit manipuliert werden kann. Oder sprecht ihr hier über einen Spezialfall dieser Funktion? Macht euch mal keine Sorgen, die Syntax kriege ich schon irgendwie hin :)) mir ist nur der Gedankengang nicht ganz klar
-
Also ich habe jetzt das mal ausprobiert, allerdings habe ich nicht die winsock2.h sondern nur die winsock.h includiert, die konstante gibt es dort aber auch. Allerdings werden immer 4 Zeichen empfangen und die Anzahl der Daten die am Socket warten soll 0 sein, hier der code:
int bytecounter = 0; char* recbyte = NULL; unsigned long* bytes = new unsigned long []; //Anzahl der wartendem Bytes bestimmen und Speicher reservieren rc = ioctlsocket (daMember[counter].Socket, FIONREAD, bytes); bytecounter = *bytes; recbyte = new char [bytecounter]; //Struktur auslesen recv (daMember[counter].Socket, recbyte, bytecounter, 0); cout << recbyte << endl;
-
hallo? wieso schreibt keiner mehr?