Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
07.07.2007, 00:56
Felheart



Hi,
wenn ich etwas von meinem Client an den Server sende muss dessen
recv funktion wissen wie viele daten aus dem empfangsbuffer gelesen
werden sollen.

Bei statischer größe von den Packetes die versendet werden kein problem,
aber wenn ich jetzt nur ein einzelnes byte (z.B. einen steuercode)
senden will wird trozdem die ganze struktur mitgesendet.
Dh: bei einer z.B. 1024 byte große struktur eben 1023 bytes zu viel gesendet

Ich hab mir bis jetzt noch keinen reihm darauf machen können wir dieses
Problem (variabele länge der Nachrichten / packets) bei spielen oder so
gelöst ist.

Zur not hab ichs jetzt gerade so gemacht das immer genau 4bytes
(ein einzelenes int) zuerst zum server gesendet werden,
dann weis der server aus der zahl(welche die grösse des nachfolgenden packets angiebt) wie viel speicher er bereitstellen muss / wie viel er
mit recv aus dem puffer lesen muss.

Kann mir wer den denkanstoss geben wie man soetwas elegant lösen kann ?

--

zum Seitenanfang zum Seitenende Profil || Suche
001
07.07.2007, 11:30
Mazze



Hi.

Hab zwar lang nichts mehr gemacht, mit dem Zeug, aber ich glaub recv() will nur wissen, wie viele Daten _maximal_ gelesen werden sollen.
http://www.zotteljedi.de/doc/socket-tipps/recv.html

cu

--

BattleTech-MOD:
http://bthl.unitedgaming.net/


Dieser Beitrag wurde am 07.07.2007 um 11:31 von Mazze bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
002
07.07.2007, 11:44
Felheart



Genau das ist ja mein problem :/
Ich erleutere mal was ich meine anhand eines beispiels

Client sendet: "123"
Im empfangsbuffer vom server ist jetzt: "123"
bei einem recv(sock, buf, 99999) erhalte ich jetzt: 123

So weit so gut.
Jetzt mal wenns problematisch wird:

Client sendet: "12345"
Client sendet: "678910"
Im empfangsbuffer des servers ist jetzt "12345678910"

Das Problem hierbei ist jetzt, wenn ich jetzt recv(sock, buf, 99999)
mache erhalte ich ja "12345678910" anstatt nur "12345" und dann bei
einem 2. aufruf "678910"
Warum ? Weil der Server (besser das recv) nicht weis wie gross die einzelnen
Packets sind.

Inzwischen ist mir aber eine idee gekommen die beiden Packets zu einem
zu verbinden
also:
Quellcode:struct Packet
{
size_t size;
char buffer[5000]; // muss nicth immer voll sein !!!  das ist das problem
};
so kann ich dann mit dem Server immer bei recv die ersten 4bytes lesen
um zu erfahren wie groß der (und das kann ja immer anders sein)
rest des Packets ist!

Meine Frage: Kann man so etwas nicht eleganter lösen ?
Ohne Header ? Wie ist das bei Spielen gemacht ?

--


Dieser Beitrag wurde am 07.07.2007 um 11:45 von Felheart bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
003
07.07.2007, 14:49
feigling



Du könntest einfach select() benutzen, welches dir sagt, wenn neue Daten zum Lesen bereitstehen. Dann *dürfte* es nicht mehr passieren, dass 2 Nachrichten hintereinandergehangen werden. Oder aber du schickst nen Trennzeichen mit, z.b. \n und splittest einfach die Nachrichten an dem Trennzeichen.

--

zum Seitenanfang zum Seitenende Profil || Suche
004
07.07.2007, 15:24
dp
Administrator


tcp wird von deinem betriebssystem konzeptuell als stream (http://de.wikipedia.org/wiki/Datenstrom) zur verfuegung gestellt, wenn du irgendwelche logischen einheiten haben willst, kommst du um einen header nicht drum rum.

du musst auch nicht jedesmal genau n byte pro nachricht schicken, eine laengenangabe und dann genau soviele bytes reichen voellig aus.

Zitat:
feigling postete
Du könntest einfach select() benutzen, welches dir sagt, wenn neue Daten zum Lesen bereitstehen. Dann *dürfte* es nicht mehr passieren, dass 2 Nachrichten hintereinandergehangen werden. Oder aber du schickst nen Trennzeichen mit, z.b. \n und splittest einfach die Nachrichten an dem Trennzeichen.
doch, kann und wird immer noch passieren. trennzeichen ist eine alternative zu einem header mit laenge.

--


Dieser Beitrag wurde am 07.07.2007 um 15:27 von dp bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
005
07.07.2007, 16:12
feigling



Ah, war mir da jetzt nicht so sicher, ob select und recv dann so schnell sind und ne Nachricht abholen, auch wenn die Gegenseite ohne Verzögerung 2 Nachrichten senden. Daher auch das *dürfte* da ich mir nicht zu 100% sicher war.

--

zum Seitenanfang zum Seitenende Profil || Suche
006
07.07.2007, 16:54
oxff



Das kann man mit select allein schon deshalb nicht loesen, da ein TCP Client normalerweise nicht stumpf fuer jeden Aufruf von send ein neues TCP Packet generiert, sondern in einem Kernel-Buffer erstmal sammel -- das ist ganz unabhaengig von der select-Performance serverseitig. Dieses ``Sammelverhalten'' kann man mit SO_NODELAY fuer interaktive Geschichten wie SSH allerdings abschalten, sollte man aber normalerweise nicht.

Soweit ich weiss, werden Daten gebuffered, solange noch ein ACK aussteht und der Buffer nicht voll ist -- genaues findet man entsprechend mit Google. Wie dp schon sagte, ist das aber ohnehin grober Bloedsinn, da TCP streamorientert und nicht paketorientiert arbeitet -- um einen eigenen Header kommst du also nicht herum.

--

mwcollect - mein Projekt | oxlog - mein blog | happyhardcore.com Stream - gute Musik

zum Seitenanfang zum Seitenende Profil || Suche
007
07.07.2007, 17:26
Felheart



jo,
aber wenn ich ein nachricht habe die die newline zeichen enthält(z.B. en liste)
dann hab ich beschädigte packets!

also ist das mit headern wohl die einzigste möglichkeit.
Thx

--

zum Seitenanfang zum Seitenende Profil || Suche
008
07.07.2007, 18:19
feigling



Ähm, man könnte vorhandene Newlines im Text auch durch \\n ersetzen und dann wieder zurückersetzen. Geht alles ;) Oder aber man nimmt ne Zeichenfolge, um nen Paket abzuschließen, \r\n oder so.

--

zum Seitenanfang zum Seitenende Profil || Suche
009
08.07.2007, 15:21
default



nonblocking sockets, rx io buffern, parsen, segemente weiterverarbeiten

--

Du musst Deine Bandbreite verbreitern, damit du breiter wirst von der Bandbreite her und ein breiteres Publikum ansprechen kannst.

zum Seitenanfang zum Seitenende Profil || Suche
010
11.07.2007, 19:05
Alcapone



Ich kenn mich nicht mit C++ aus, denn ich programmiere in C#, aber es gibt im DotNet Framework ein Property, die Available heisst. Anhand der Property kann ich herrausfinden, wieviele Daten im Buffer zur Verfügung stehen. In einer While schleife rufe ich dann die Daten, die sich im Buffer befinden, ab, bis Available 0 ist. Ich denke bei C++ gibts auch so was ähnliches.

Zum anderen Problem: Probiers mit Headern, wie es vor mir schon erwähnt wurde.

--

"Everything, that can go wrong, will go wrong" Murphy's Law

zum Seitenanfang zum Seitenende Profil || Suche
011
11.07.2007, 21:02
dp
Administrator


Zitat:
Alcapone postete
Ich kenn mich nicht mit C++ aus, denn ich programmiere in C#, aber es gibt im DotNet Framework ein Property, die Available heisst. Anhand der Property kann ich herrausfinden, wieviele Daten im Buffer zur Verfügung stehen. In einer While schleife rufe ich dann die Daten, die sich im Buffer befinden, ab, bis Available 0 ist. Ich denke bei C++ gibts auch so was ähnliches.
gibt es nicht. waere aber auch nicht relevant, weil man dadurch immer noch nicht wuesste, wo ein "paket" anfaengt und aufhoert. lesen bis im buffer 0 bytes zurueckbleiben kann man auch mit einem nicht blockenden recv bis man errno=EAGAIN bekommt.

--

zum Seitenanfang zum Seitenende Profil || Suche