Bei send() und recv() wirklich ALLES senden bzw. empfangen?



  • recv = 0 bedeutet socket beendet, sonst blockiert recv solange bis daten kommen oder wirft glaube nen timeout in wsagetlaserror() (ausgenommen nonblocking mode)



  • Ich habe auch mal so eine Empfangsschleife gebaut und auch seltsammte Effekte festgestellt die auf manchen Implementierungen und Compilern auftreten.

    Wenn man dein Programm betrachtet, dürfte ja nichts fehlen, da du in einer Schleife abfragst wieviel empfangen wurde

    if((nread = recv(fd, ptr, nleft, 0)) < 0)
    

    und dann berechnest, wieviel nachgeladen werden muß und an welche Stelle

    nleft = nleft - nread; 
    ptr = ptr + nread;
    

    Dabei tritt ein Fehler auf, da fread anscheinend bei manchen Compilern immer mindestens um die groesse des Struct weiterrückt.

    Ich meine Folgendes.
    Du hast z.B. ein Strukt der groesse 12 Byte. Sagen wir mal 4 Byte wurden empfangen.
    Jetzt berechnest du, dass 8 Byte nachgeladen werden müssen und 4 wurden schon geladen.
    Da aber ein Strukt 12 Byte groß ist versucht recv die 8 Byte an Position
    4 + 12= 16 Byte nachzuladen, weil es um die Groesse des Struct vorrückt. Somit wird fremder Speicherbereich überschrieben und das Strukt ist unvollständig.
    (Oder es sieht so aus, dass der Rest im nächsten Struct kommt)

    Das erklährt deine Beobachtung:
    [quote] Beim Server kommt irgendwie nicht immer alles an bzw. ein Paket kommt nicht vollständig an und ein Rest des Paketes kommt hinterher[quote]

    Wenn du ein Sleep(500) einbaust, wird sichergestellt, dass soviel da ist um ein
    Struct voll zu beschreiben und der Fehler passiert nicht. Dies kann aber aufgrund der Groesse nicht im Sinn des Erfinders sein.

    Eine Lösung währe es erst alles in ein array von chars einzulesen (Wieder in der Schleife mit der selben char Arraylänge wie dein Struct) und dann anschließend in die gewünschte Struct zu casten. Dann verrechnet sich recv nicht bei der Speicherposition.

    Jetzt werden bestimmt einige sagen:"So nen quatsch, rechv rückt nicht um die Länge des Struct vor"
    Aber ich habe genau DISES schon nachvollziehen können und es passiert wirklich. Außerdem beschreibt es GEANU den hier geschilderten Fehler!

    Das komische ist, das der Effekt bei manchen Compilern auftritt, bei anderen nicht.



  • @MisterX :

    Bei fwrite/fread gibst du die Grösse der "Einheit" mit, und zusätzlich nochmal die Anzahl der "Einheiten". Bei send/recv ist das nicht so -- da gibts nur die Anzahl der Bytes.
    Woher soll send oder recv wissen dass der Zeiger der da übergeben wird auf ein struct zeigt?
    Ne, daran *kann* es nicht liegen. Und wenn du 100 mal sagst es ist so sag ich 101 mal es kann nicht sein.

    Es kann höchstens daran liegen dass man vielleicht die Regeln der C bzw. C++ Zeigerarithmetik nicht verstanden hat. Wer natürlich nen Zeiger auf die Struktur verwendet, und auf den dann "+= n" macht, der muss sich nicht wundern wenn der Zeiger um n Strukturen und nicht n chars weiterwandert. Wer aber "+= n" auf nen char Zeiger macht wird den char Zeiger um n chars weiterrücken.

    Obwohl... ich kenne einen "C Compiler" der das falsch umgesetzt hat, also Zeiger immer um n chars weitergerückt hat, egal welchen Typs der Zeiger war. Bloss das ist 15 Jahre her, und das Teil war damals schon Schrott.

    Das alles stellt aber im hier geposteten Code kein Problem dar, da hier brav mit char Zeigern gearbeitet wird. Blubb.

    p.S.: du hast nicht zufällig noch Code der davon betroffen ist? Und den Namen je eines Compilers wo es geht bzw. nicht geht? Wäre interessant...

    p.p.S.: recv rückt *garnicht* vor. recv gibt bloss zurück wieviel gelesen wurde. Vorrücken muss man selbär. Nur so nebenbei.



  • mal abgesehen von euren einwänden (die ich nicht im detail gelesen habe), wenn du ein struct von 12 bytes hast heißt das nicht unbedingt das das nachfolgende struct an position 13 anfängt, stichwort "speicherausrichtung" ...
    meine frage daher welchen compiler verwendest du?
    versuch es mal mit 4 dummy bytes in deiner struct am ende damit die structgröße durch 8 teilbar ist oder (falls du borland verwendest)

    #pragma pack(push, 1)
    
    //dein struct
    
    #pragma pack(pop)
    

    ich kann mich noch an schulzeit erinnern, da gab es irgendwie ein __attribute_packed oder so ähnlich was man bei der struct definition einfügen kann um ähnliche effekte zu erzielen

    EDIT ich arbeite hier mit structs und anderen daten im größenverhältnis bis 2000 bytes und hab absolut keine probleme, ich versteh nich was da mit sleep helfen soll, ... es hilft einzig und allein nur das du pro sekune nur 2 pakete empfangen kannst -.-



  • @Ceos: wenn man über sizeof(struct) geht ist es egal wie die Struktur gepackt wird. Natürlich muss das Packing beim Client und beim Server gleich sein, klar.



  • naja, was ich meine, wenn er um BYTES inkrementiert zwischen den structs aber verlorene bytes liegen kann doch gut sein das bis zu 7 byte verloren gehn



  • Jo, OK. Aber wer tut schon sowas böses 😉



  • ich weis zwar nichtmehr wo genau aber ich hatte etwas ähnliches (ich glaub es war ne diskrepanz zwischen 2 projekten die über netzwerk kommunizierten) in dem moment hast natürlich du recht, wenn zwischen beiden programmen die speicherausrichtung stimmt müsste es normal funktionieren



  • EDIT ich arbeite hier mit structs und anderen daten im größenverhältnis bis 2000 bytes und hab absolut keine probleme, ich versteh nich was da mit sleep helfen soll, ... es hilft einzig und allein nur das du pro sekune nur 2 pakete empfangen kannst -.-

    Das das slepp(500) hilft untersctützt wieder meine Theorie, dass es in dieser einleseschleife schiefgeht. Denn wenn man ne halbe sekund wartet ist die Wahrscheinlichkeit, das das paket mitlerweile ganz da ist doch ziemlich groß.
    Dann wird es auf einen Schlag in die Struckt geschreiebn und diese Einleseschleife, mit dem Falschen "vorrücken" wird nicht bbenutzt. Denn die Daten sind ja auf einen Schlag vorhanden.

    Das mit dem Warten auf das sleep ist natürlich keine Lösung die man anstreben sollte. Teste doch wirklich mal Alles erst in nem char Array einzulesen (in der Schleife) und erst dann in die Struckt zu casten. Wenns nicht hilft ist Meine Theorie falsch, aber testen kannstes ja mal. (Vorallem da es keine bessere Lösungstrategie hier gibt)

    Obwohl... ich kenne einen "C Compiler" der das falsch umgesetzt hat, also Zeiger immer um n chars weitergerückt hat, egal welchen Typs der Zeiger war. Bloss das ist 15 Jahre her, und das Teil war damals schon Schrott.

    PS. Mir ist der Fehler mit dem Visual C++ 6.0 aufgefallen, in der ursprünglichen Version ohne SDK updates.
    (Der war zwar auch schrottig, ist aber noch keine 15 jahre her 😃 )



  • (Vorallem da es keine bessere Lösungstrategie hier gibt)

    Sorry,
    ich hatte die Idee mit den 4 Dummy Bytes überlesen. Teste erst mal das und wenns nicht hilft meine Idee. Denn das mit den 4 Dummy Bytes ist wohl erst mal weniger Arbeit 😃


Anmelden zum Antworten