Puffer säubern



  • Hallo zusammen,

    und zwar möchte ich ein std::array cleanen. Vielleicht steckt mein Fehler aber auch darin wie ich mit std::array umgehe.
    Und zwar möchte ich eingehende Daten in einen String einlesen. Das sieht zum Beispiel beim mir so aus:

    std::array<char, 1024> buffer;
    stream.read_some(boost::asio::buffer(buffer, sizeof(buffer)), error);
    std::string incoming ;
    incoming = buffer.data(); //Ich glaube das hier ist schon keine schöne Lösung.
    

    Nun ist das nächste Problem, dass wenn ich das ganze in einer Schleife habe, der buffer noch voll ist.
    Bekomme ich also beim ersten mal "Otto lacht" gesendet und beim zweiten mal nur "Alex", so landet in meinem String "Alex lacht".
    Um das zu vermeiden habe ich bis jetzt immer buffer.fill(0) benutzt. Aber auch das scheint mir sehr unschön dafür.

    Ihr habt bestimmt bessere Ideen wie man das Ganze ordentlich umsetzt. Wie kann ich die Problematik also sauber lösen?



  • Ich kenne mich mit boost::asio zwar nicht aus, aber read_some hat einen Return-Wert... Und std::string hat einen Constructor für from-buffer (Nummer 5 hier: http://www.cplusplus.com/reference/string/string/string/)



  • @zhavok sagte in Puffer säubern:

    Hallo zusammen,

    und zwar möchte ich ein std::array cleanen. Vielleicht steckt mein Fehler aber auch darin wie ich mit std::array umgehe.
    Und zwar möchte ich eingehende Daten in einen String einlesen. Das sieht zum Beispiel beim mir so aus:

    std::array<char, 1024> buffer;
    stream.read_some(boost::asio::buffer(buffer, sizeof(buffer)), error);
    std::string incoming ;
    incoming = buffer.data(); //Ich glaube das hier ist schon keine schöne Lösung.
    

    Nun ist das nächste Problem, dass wenn ich das ganze in einer Schleife habe, der buffer noch voll ist.
    Bekomme ich also beim ersten mal "Otto lacht" gesendet und beim zweiten mal nur "Alex", so landet in meinem String "Alex lacht".
    Um das zu vermeiden habe ich bis jetzt immer buffer.fill(0) benutzt. Aber auch das scheint mir sehr unschön dafür.

    Ihr habt bestimmt bessere Ideen wie man das Ganze ordentlich umsetzt. Wie kann ich die Problematik also sauber lösen?

    Wenn du mit Puffern ( insbesondere in Verbindung mit Sockets ) arbeitest, solltest du immer die Anzahl der Bytes ( die du empfangen hast ) mit berücksichtigen. In dem Fall ist dann unerheblich was in dem Puffer steht.
    Du schreibst dort "Alex" rein, weiß aber dass du nur 4 Byte empfangen hast. Somit ist irrelevant was im Puffer ab Offset 4 steht.
    Man kann das ganze noch viel weiter treiben, wenn man davon ausgeht, dass man nicht jede Message immer komplett empfängt ( erster Teil der Message "Al", zweiter Teil der Message "ex" ). Aber das wird für deinen Anwendungsfall nicht unbedingt notwendig sein.

    Korrekt wäre für dich vermutlich irgendwas wie:

    std::array<char, 1024> buffer;
    auto BytesReceived = stream.read_some(boost::asio::buffer(buffer, sizeof(buffer)), error);
    std::string incoming( buffer.data(), BytesReceived  );
    

    Ich bin aber kein Boosti, daher kann ich nur mutmaßen.



  • @zhavok
    leg buffer erst in der Schleife an.



  • Richtig. read_some() gibt die Anzahl der Bytes zurück. Sobald ich aber die Variante verwernde von @It0101 also bei mir:

    size_t bytes = stream.read_some(boost::asio::buffer(buffer, sizeof(buffer)), error);
    incoming = (buffer.data(), bytes);
    

    Ist mein incoming immer leer. So ähnlich hatte ich es schon davor. Ich hatte incoming mit einer Schleife aufgebaut:

    size_t bytes = stream.read_some(boost::asio::buffer(buffer, sizeof(buffer)), error);
    for(size_t i; i < bytes; i++) {
        incoming += buffer[i];
    }
    

    Führte aber zum gleichen Fehler. Hier übrigends mal der komplette Code. Vielleicht liegt da irgendwo der Fehler. (Wenn dann wahrscheinlich nach dem Start SSL Socket Block)

    #include <iostream>
    #include <string>
    #include <array>
    #include <fstream>
    #include <boost/bind.hpp>
    #include <boost/asio.hpp>
    #include <boost/asio/ssl.hpp>
    
    typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
    
    std::string pass() {
    	return "test";
    }
    
    int  main() {
    
    	while (true) {
    
    		std::cout << "Server started..." << std::endl;
    
    		try {
    			
    			//Start TLS Socket
    			boost::asio::io_service io_context;
    			boost::asio::ip::tcp::acceptor acceptor(io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 11880));
    			boost::asio::ssl::context context(boost::asio::ssl::context::sslv23);
    			context.set_options(
    				boost::asio::ssl::context::default_workarounds
    				| boost::asio::ssl::context::no_sslv2);
    			context.use_certificate_chain_file("public.pem");
    			context.set_password_callback(boost::bind(pass));
    			context.use_private_key_file("private.pem", boost::asio::ssl::context::pem);
    			context.use_tmp_dh_file("dh2048.pem");
    			ssl_socket stream(io_context, context);
    			boost::asio::ip::tcp::endpoint peer_endpoint;
    			acceptor.accept(stream.lowest_layer(), peer_endpoint);
    			boost::system::error_code ec;
    			stream.handshake(boost::asio::ssl::stream_base::server, ec);
    
    
    			std::string response;
    			std::string incoming;
    			std::array<char, 1024> buffer;
    
    			boost::system::error_code error;
    			
    			buffer.fill(0);
    			size_t bytes = stream.read_some(boost::asio::buffer(buffer, sizeof(buffer)), error);
    			incoming = (buffer.data(), bytes);
    
    			std::ofstream Output("Log.txt");
    			Output << incoming;
    			Output.close();
    
    			std::cout << incoming << std::endl;
    
    			response += "ist angekommen: (" + incoming + ")";
    			boost::asio::write(stream, boost::asio::buffer(response, response.length()));
    
    
    		}
    		catch (std::exception& myexc) {
    			std::cout << myexc.what() << std::endl;
    		}
    	}
    }
    


  • @zhavok sagte in Puffer säubern:

    sizeof(buffer)

    OT: wozu hat std::array wohl eine size Funktion?



  • ohja, wow. Ich weiß selbst nicht warum ich hier sizeof geschrieben habe, das verwende ich eigentlich nie^^.



  • @zhavok sagte in Puffer säubern:

    Richtig. read_some() gibt die Anzahl der Bytes zurück. Sobald ich aber die Variante verwernde von @It0101 also bei mir:

    size_t bytes = stream.read_some(boost::asio::buffer(buffer, sizeof(buffer)), error);
    incoming = (buffer.data(), bytes);
    

    wenn dann so:

    incoming = std::string(buffer.data(), bytes);
    

    oder

    incoming.append( buffer.data(), bytes );  // Falls du sicherstellst, dass incoming zuvor leer ist
    


  • Ahja, sehr schön. So ist es doch gleich viel besser. Funktioniert auch genau so wie es soll. Vielen Dank! Ich denke so kann ichs lassen.
    Nur eine Frage noch: Wie sollte es denn aussehen wenn man std::array doch einmal für irgendeinen Fall clearen muss?



  • @zhavok sagte in Puffer säubern:

    Ahja, sehr schön. So ist es doch gleich viel besser. Funktioniert auch genau so wie es soll. Vielen Dank! Ich denke so kann ichs lassen.
    Nur eine Frage noch: Wie sollte es denn aussehen wenn man std::array doch einmal für irgendeinen Fall clearen muss?

    SocketBuffer cleart man nicht. Da schreibt man einfach drüber. Kann man zwar tun, ist ist aber nutzlos.
    Ich benutze std::array leider kaum, weil die Länge zur Compilezeit feststehen muss und ich das im allgemeinen flexibel brauche. Die Länge eines SocketBuffer z.B. will man manchmal auch in einer INI-Datei vorher festlegen und schon fällt std::array raus.

    ansonsten geht sowas immer:

    std::array <char, 1024> buffer;
    memset( buffer.data(), 0, buffer.size() );
    

    Das ist aber prinzipiell ANSI-C und kein C++ mehr. Deswegen würde man damit im C++-Bereich zurecht auf Kritik stoßen.

    Edit: versuch mal das:

    std::fill( buffer.begin(), buffer.end(), 0 );
    


  • Da muss ich mal ganz dümmlich fragen, wo ist der Unterschied zwischen:

    std::fill( buffer.begin(), buffer.end(), 0 );

    und

    buffer.fill(0);

    ?

    Beides setzt doch eigentlich alle Werte des Arrays auf 0?



  • @zhavok sagte in Puffer säubern:

    Da muss ich mal ganz dümmlich fragen, wo ist der Unterschied zwischen:

    std::fill( buffer.begin(), buffer.end(), 0 );

    und

    buffer.fill(0);

    ?

    Beides setzt doch eigentlich alle Werte des Arrays auf 0?

    Hast Recht. Sollte beides das gleiche tun. Geht denn wenigstens eine der beiden Varianten?



  • std::fill hab ich nicht getestet. Aber buffer.fill() funktioniert. Ich gehe stark davon aus, std::fill wird auch ohne Probleme funktionieren^^. Muss leider erstmal los.

    Vielen Dank @all für die vielen Tipps 👍🏻



  • fill mit 0 oder memset mit 0 am Ende des Lebensbereiches des Buffers kann vom Compiler wegoptimiert werden. Wenn, dann memset_s, SecureZeroMemory oder ähnliches nutzen.


Anmelden zum Antworten