boost::asio::write(), große data-chunks, socket-error 10053



  • hustbaer schrieb:

    @Kóyaánasqatsi:
    Das stimmt so nicht. 1 MB mit TCP zu übertragen ist überhaupt nicht riskant

    Doch, ist sehr wohl riskant: http://de.wikipedia.org/wiki/Maximum_Transmission_Unit

    Klar geht auch mehr, aber 1MB mit einem Batzen rüberzuprügeln ist schon etwas viel, meinst du nicht? 😕



  • *facepalm*

    Nein, meine ich nicht.
    Nochmal: TCP zerlegt das selbständig in Fragmente die kleiner als die MTU des IP-Stacks sind, und übergibt diese Fragmente dann an IP. Der Empfänger bastelt das Ganze wieder zusammen.

    Was soll da Probleme machen?



  • Wie mach man es denn richtig? Zum beispiel die "Großen" - wie machen die das? Stückeln die ihre Messages und schicken sie nach und nach raus? Denn auch ich dachte, wie ihr, dass der TCP-Stack das schon für mich übernehmen würde.



  • Denn auch ich dachte, wie ihr, dass der TCP-Stack das schon für mich übernehmen würde.

    Tut er auch. Wie sieht denn die Client Seite aus? Tritt ev. dort ein Problem mit viel Daten auf (egal ob in Chunks oder als Ganzes)?



  • Also ich bau mir nen std::vektor, bestehend aus unsigned chars zusammen den ich dann senden will. write() wird ein mal mit dem ganzen teil (vektor) aufgerufen. Bei kleinen datenmengen gibts keine probleme (zumindest keine, die ich im LAN feststellen würde), bei großen hingegen tritt der besagte 10053er fehler auf. Der server, an den geschickt wird, hat ein select, mit dem er checkt ob an nem port was anliegt und dann ggf. recv() aufruft. Ich mein, das hat sich doch über jahrzehnte hinweg bewährt, warum gibts da jetzt stress? irgendwas läuft da faul. ich werd nachher mal bisschen betreffenden code posten, vielleicht könnt ihr da was auf anhieb erkennen.



  • Kóyaánasqatsi schrieb:

    hustbaer schrieb:

    @Kóyaánasqatsi:
    Das stimmt so nicht. 1 MB mit TCP zu übertragen ist überhaupt nicht riskant

    Doch, ist sehr wohl riskant: http://de.wikipedia.org/wiki/Maximum_Transmission_Unit

    Klar geht auch mehr, aber 1MB mit einem Batzen rüberzuprügeln ist schon etwas viel, meinst du nicht? 😕

    Du verwechselst das wohl mit der http://de.wikipedia.org/wiki/Maximum_Segment_Size

    Ich würde vermuten der Outgoing-Buffer ist voll.
    Probiers doch einfach mal mit einem boost::asio::asnyc_write().



  • @i8087:
    Ich vermute eher dass das Problem beim Server liegt. Oder kannst du das sicher ausschliessen?

    Und ja: etwas Code von Client & Server würde nicht schaden.

    @nurf:

    Ich würde vermuten der Outgoing-Buffer ist voll.

    Ich sehe nicht wie bei TCP mit der klassischen Sockets API ein "Outgoing-Buffer" voll sein sollte. Bzw. genauer: wie dieser Umstand zu einem Problem führen sollte, abgesehen davon dass irgendwas etwas länger dauert.
    Es kann ja immer der vom Aufrufer übergebene Puffer verwendet werden. Dieser muss ja bis zum Abschluss des send() gültig bleiben (ganz egal ob send() nun synchron oder asynchron läuft).

    Oder meinst du was anderes?



  • Ich verwende in solchen Faellen wireshark und seh mir genau an wo der Fehler auftritt.

    Meistens liegt so ein Fehler am Server, wie hustbaer schon gesagt hat.

    Und TCP kann sehr wohl jeder Art von Daten umgehen. MSS und MTU haben nichts damit zu tun. Die sind fuer den Application Layer naemlich komplett uninteressant. Die sind fuer den Transport der einzelnen TCP Pakete wichtig - aber das ist ein komplett anderer Layer.

    Man kann btw ueber TCP auf ganze Terabyte an Daten uebertragen 😉



  • Shade Of Mine schrieb:

    Man kann btw ueber TCP auf ganze Terabyte an Daten uebertragen 😉

    Da brauchst du aber eine große Porno-Sammlung 🤡



  • /dev/random tuts auch



  • Pr0n möchte ich nicht damit übertragen. Sonst platzen mir die kommunikationspartner weg
    Jedenfalls hier mein write()-Aufruf:

    boost::system::error_code boostTransmissionErrorCode;
    // bytesWritten soll ja dieselbe Größe haben wie localCpy.size()
    // das trifft jedoch eben manchmal nicht zu. Wenn dies nicht zutrifft, wird in boostTransmissionErrorCode der besagte Fehler geschrieben.
    // lässt man boostTransmissionErrorCode weg, wird eine exception geworfen.
    bytesWritten = boost::asio::write(*(socket), boost::asio::buffer(&localCpy[0],localCpy.size()), boost::asio::transfer_all(), boostTransmissionErrorCode); 
    recv();
    

    Auf der Server-Seite sieht das ganze so aus:

    EDIT: Sorry, vergessen den servercode zu pasten

    // hier vielleicht interessant, das select
    		if( ( n = select( fd_skt+1, &rd_set , NULL, NULL, &tv)) > 0 ){
    
    			do{
    				uiRsize = m_TCPCon->recv(&vucRec[0], RECSIZE, 0);
    				// instanzmethode ruft einfach nur auf	
    				//recv(m_TCPCon->m_iSocketDescriptor,buffer,RECSIZE,0);
    
    				sizeCounter += uiRsize;
    
    				switch (uiRsize){
    					case -1: // fehl0r
    						// irrelevanter code
    						break;
    					case 0: // nix
    						// irrelevanter code
    						break;
    					default: // etwas empfangen
    						// schreib das zeug in den ergebnispuffer
    						vucRec.resize(uiRsize);
    						vucData.insert( vucData.end(), vucRec.begin(), vucRec.end() );
    						vucRec.clear();
    				}
    				vucRec.resize(RECSIZE);
    
    				usleep(100); // je hoeher man den krempel stellt, desto mehr wird empfangen.
    
    			} while( uiRsize == RECSIZE); // mach den kram so lange nicht weniger als RECSIZE Bytes empfangen wurden
    
    			sprintf(sizeCounterString, "sizeCounter=%d",sizeCounter);
    			logger.logWarning("Empfangen:",sizeCounterString);
    			this->processInData(vucData);
    


  • Dieser Server ist ja extrem ressourcenschonend!



  • Ja, Fehler liegt im Server. Fehler weil Doku nicht gelesen. DER Klassiker bei der Sockets API schlechthin.

    // } while( uiRsize == RECSIZE); // mach den kram so lange nicht weniger als RECSIZE Bytes empfangen wurden
    // so geht das aber nicht.
    // SO geht das:
     } while(uiRsize > 0); // mach den kram so lange neue daten empfangen wurden
    

    Jetzt hast du natürlich ein anderes Problem, nämlich dass dein Server nicht mehr weiss wann er aufhören darf/kann/muss.

    Das löst du am besten indem du vor dem Datenblock noch die Grösse des Datenblocks überträgst.



  • hustbaer schrieb:

    DER Klassiker bei der Sockets API schlechthin.

    Wieso bei Sockets API?
    Generell bei Streams, nur fällt es anders häufig nicht auf 😉



  • Socket? schrieb:

    hustbaer schrieb:

    DER Klassiker bei der Sockets API schlechthin.

    Wieso bei Sockets API?
    Generell bei Streams, nur fällt es anders häufig nicht auf 😉

    Ich hab einfach die Beobachtung gemacht, dass es Leute bei anderen Streams checken, aber bei der Sockets API nicht.

    Vermutlich deswegen, weil sie glauben dass eine Socket-Verbindung kein "reiner" Stream ist, sondern irgendwie "Paketgrenzen" berücksichtigt und mitüberträgt.

    Und natürlich fällt man bei anderen Streams sofort auf die Schnauze -- wenn man versucht sowas mit einem File auf ner Platte zu machen geht es gleich beim 1. mal nicht, und man weiss sofort dass man ein "Problem hat" (=es eben anders machen muss).

    Bei TCP Streams dagegen kann es überraschend lange funktionieren (immer schön kleine Pakete, so dass nie ein send() zu mehr als einem TCP Paket führt, immer schön Flusswechsel nach jedem Paket - dann kann das "ewig" gutgehen).

    Dann (also wenn jemand das "Funktionieren" dieser "Technik" bereits beobachtet hat, es aber "auf einmal" nicht mehr "funktioniert") kommen übrigens auch die lustigen bzw. nervigen (je nachdem wie man es aufnimmt) Beiträge ala "glaub ich dir nicht, weil das mach ich schon immer so, und das hat bis jetzt immer funktioniert" 😉


Anmelden zum Antworten