Binmode STDOUT



  • Ok, dann versuche ich nicht, das weiter zu verstehen.

    Du kannst aber sowas bauen, wenn der Code nur für Windows-Plattformen ausgeführt werden soll (entsprechendes Makro prüfen, heißt das bei dir _WINDOWS oder anders):

    #ifdef _WINDOWS
       #include <io.h>
       #include <fnctl.h>
    #endif
    
    
    void set_file_binary_mode()
    {
    #ifdef _WINDOWS
       _setmode( _fileno( stdin  ), _O_BINARY  );
       _setmode( _fileno( stdout ), _O_BINARY );
    #endif
    }
    

    Edit: Quelltext nach MS-Doku angepasst



  • @DocShoe sagte in Binmode STDOUT:

    Ok, dann versuche ich nicht, das weiter zu verstehen.

    Du kannst aber sowas bauen, wenn der Code nur für Windows-Plattformen ausgeführt werden soll (entsprechendes Makro prüfen, heißt das bei dir _WINDOWS oder anders):

    #ifdef _WINDOWS
       #include <fnctl.h>
    #endif
    
    
    void set_file_binary_mode()
    {
    #ifdef _WINDOWS
       _setmode( STDIN_FILENO, O_BINARY );
       _setmode( STDOUT_FILENO, O_BINARY );
    #endif
    }
    

    Gute Idee!!!

    Danke!!

    PS: _WIN32



  • @_ro_ro sagte in Binmode STDOUT:

    @DocShoe sagte in Binmode STDOUT:

       _setmode( STDOUT_FILENO, O_BINARY );
    

    Gute Idee!!!

    Und? Funktioniert das? Irgendwie habe ich solche Tools bisher nur für Linux geschrieben, aber es wäre gut, wenn sowas dann ohne viel Aufwand auch unter Windows laufen würde. Diese Datenverarbeitungs-Pipelines, die man damit via Kommandozeile zusammenstöpseln kann sind ja schon extrem praktisch:

    cat file | tool1 | tool2 | tool3 > processed_file



  • @_ro_ro Verstehe ich dein Anliegen richtig, dass du das Gif als Binary direkt ins HTML schreiben möchtest? Ich würde mutmaßlich, das Gif in eine extra Datei schreiben und die Datei ins HTML einbinden.

    Deine Lösung gefällt mir persönlich nicht. Das scheint irgendwie speziell auf die beiden Systeme mit denen du arbeitest zugeschnitten zu sein ohne das du garantieren kannst, dass das auf einem dritten System jetzt auch funktioniert.

    Was du sonst versuchen kannst, ist, durch den String zu iterieren und aus einzelnen Chars ein std::bitset machen und das mit to_string() dann konvertieren.

    Wo ich gerade nach Binary Darstellungen von Bildern in HTML google, willst du das wirklich als Binary darstellen? Ich finde nur Base64 encodierte ASCII String representation, aber ich bin in Webtechnologien auch echt schlecht.



  • @Schlangenmensch sagte in Binmode STDOUT:

    @_ro_ro Verstehe ich dein Anliegen richtig, dass du das Gif als Binary direkt ins HTML schreiben möchtest?

    Nein. Und es geht ja auch nicht nur um Grafiken oder PDF oder Zip-Dateien oder sonstige Binaries die nach stdout sollen, sondern auch darum eine HTML-<textarea> im Binmode auszuliefern, da ansonsten die Zeilenumbrüche der Eingaben falsch gesendet werden bei einem Submit via POST. Also einen generellen binmode.

    Wo ich gerade nach Binary Darstellungen von Bildern in HTML google, willst du das wirklich als Binary darstellen? Ich finde nur Base64 encodierte ASCII String representation, aber ich bin in Webtechnologien auch echt schlecht.

    Jeder Webserver sendet Grafiken als Binary, ein Request like <img src="/red.gif"> weist bspw. den
    Webserver an, diese Datei im DOCUMENT_ROOT zu lesen und als Binary via HTTP zu senden.

    MFG



  • @Schlangenmensch sagte in Binmode STDOUT:

    ...
    Was du sonst versuchen kannst, ist, durch den String zu iterieren und aus einzelnen Chars ein std::bitset machen und das mit to_string() dann konvertieren.
    ...

    Das Problem scheint zu sein, dass unterschiedliche Streams zum Lesen und Schreiben der Daten benutzt werden. Wenn die Datei im Binär-Modus gelesen wird landet sie 1:1 im Speicher, beim Schreiben in die Standardausgabe ersetzt das std::cout Objekt unter Windows LF durch CR+LF, was die Binärdaten zerstört (btw: Da hätte ich von @_ro_ro auch gerne mal zwei kurze Hex-Dumps gesehen, die das Problem zeigen). @_ro_ro sucht eine Möglichkeit, diese automatische Übersetzung zu deaktivieren. Das Verhalten steckt iwo im std::cout Objekt, und da hört mein Wissen auf. Ich weiß nicht, ob man das durch das Benutzen einer eigenen locale oder stream_buf steuern kann, da müssen jetzt Leute her, die sich damit auskennen 😉

    Edit:
    Hab mir mal die MSVC Implementierung auf github angeschaut, da werden std::cinund std::cout über einen filebuf um stdin und stdout gebaut. Zusammen mit der _setmode Funktion bedeutet dass, dass das Verhalten schon in stdin und stdout steckt und unter C++ vllt überhaupt nicht bekannt ist und damit auch nicht verändert werden kann, sondern nur die zu Grunde liegenden stdin und stdout Objekte.



  • @DocShoe

    die von mir beschiebenen Effekte treten nur unter Win32 auf. XP ging sogar soweit, Dateien spontan zu verändern wenn nicht explizit im BINARY-Mode (sysopen call) darauf zugegriffen wurde. Und als ich vor 10 Jahren mal einen Parser für den grottigen Enctype multipart/form-data in C geschieben habe, musste ich auch feststellen daß C unter Windows per Default keinen Binmode stdin/stdout kennt. der also explizit gesetzt werden muss. In Perl ist das eine Zeile binmode STDOUT und gut isses.

    Offensichtlich entwickelt Ihr nicht unter Win32.

    MFG



  • @_ro_ro sagte in Binmode STDOUT:

    @DocShoe
    Offensichtlich entwickelt Ihr nicht unter Win32.

    Steile These



  • @_ro_ro Hm, irgendwie verstehe ich deine Architektur noch nicht. Du baust in C++ dein HTML zusammen, schreibst das in die Konsole, und liest das dann von da aus mit einer anderen Software ein, die dann die Webseite ausliefert?

    Ich frage, weil ich nie auf die Idee gekommen wäre, eine Datei nach std::out zu schreiben

    @_ro_ro sagte in Binmode STDOUT:

    Offensichtlich entwickelt Ihr nicht unter Win32.

    Doch, professionell momentan sogar ziemlich ausschließlich. Aber ich schreibe keine Dateien in die Konsole, hängt dann ja auch noch davon ab, welche Konsole verwendet wird und wie die die Daten interpretiert.



  • @Schlangenmensch

    Ein CGI-Programm liest von STDIN und schreibt nach STDOUT. Das ist alles was ein CGI-Programm können muss 😉

    Guck Dir mal den Standard CGI/1.1 an.

    MFG



  • @Schlangenmensch

    Bei CGI Anwendungen sind cin/cout keine Konsolenstreams, sondern umgeleitete Streams des Webservers. Der leitet seine STDOUT Ausgaben in STDIN der Anwendung um und liest über sein STDIN die Daten, die die CGI Anwendung in ihren STDOUT schreibt. Das hat mit der DOS-Konsole unter Windows nichts mehr zu tun, sondern ist ein IPC Mechanismus

    (Webserver-Anwendung::stdout) => (CGI::stdin) => (CGI::stdout) => (Webserver-Anwendung::stdin)



  • @DocShoe

    Genau und als kleine Ergänzung: Die Idee hinter CGI/1.1 ist, einen Layer zu schaffen der HTTP von der Anwendung trennt.

    MFG



  • Und die Antwort auf @_ro_ro ist: geht nicht in Standard-C++, sondern ist "implementation dependent".

    Siehe https://isocpp.org/wiki/faq/input-output#binary-mode-for-cin-cout

    Hier hat jemand dasselbe gefragt: https://stackoverflow.com/questions/5654067/how-to-make-cout-behave-as-in-binary-mode und die Lösung ist im Prinzip die, die du oben schon nutzt.



  • @_ro_ro sagte in Binmode STDOUT:

    Mein CGI/c++ entwickle ich auf Windows 10

    Ah, erste Zeile mitlesen hilft.

    Dein "Production System" ist aber ein Linux, richtig? Ist zwar nicht die Lösung des geschilderten Problems, aber ich würde es dann wohl erstmal mit dem Windows Subsystem for Linux probieren um auf einer produktionsnahen Umgebung zu entwickeln.

    Ich habe auch mal kurz nach CGI Libraries gegoogelt, die scheinen vor allem FastCGI zu implementieren und damit das Problem zu umgehen.



  • @Schlangenmensch

    CGI's entwickeln heißt plattformunabhängig entwickeln. Es ist also egal ob man das auf Win32 oder Sun/OS oder Linux tut. Produktionsnah heißt nur, daß man in seiner Entwicklungsumgebung dasselbe Ergebnis bekommt. So sehe ich das und diese Haltung haben alle Unternehmen unterstützt für die ich gearbeitet habe. Was ja auch gar nicht anders umgesetzt werden kann. So habe ich Perl/CGI's entwickelt die auf Sun/Solaris, auf FreeBSD, Debian, IBM AIX und Win32 laufen mussten. Was nicht zuletzt auch einem heterogenem Campus-Netzwerk geschuldet war.

    MFG



  • @_ro_ro Mit nativen Programmiersprachen ist "Crossplattform" aber nicht unbedingt trivial. Es gibt Dinge, die sind OS abhängig, ist gibt Dinge die sind eventuell Compiler Abhängig und so weiter. Du hast jetzt eine Macro Überprüfung ob das ganze auf Windows oder Linux läuft und scheinst damit das korrekte Verhalten zu erziehlen. Was passiert, wenn du das auf einem anderen System kompilierst, weißt du aber nicht.
    Ich habe mich mit Perl nicht intensiv beschäftigt, ich würde aber vermuten, dass dir da viel der Interpreter abnimmt.

    Produktionsnah bedeutet für mich, dass sich die Systeme ähneln, insbesondere was Compiler und Betriebssystem betrifft, und ich nicht auf Entwicklungs und Produktionsumgebung unterschiedlichen Code ausführe damit es da nicht zu unerwarteten Überraschungen kommt.



  • @Schlangenmensch

    ja sicher doch. Wenn man auf einem anderen System compiliert weiß man nie was passiert 😉
    Und bei CGI/1.1 kommt noch hinzu wie der Webserver HTTP implementiert, insbesondere beim Parsen der Header. Da gibt es auch noch Unterschiede, Beispiel:

    Normalerweise parst der Webserver die Header die er von einem CGI-Prozess bekommt und toleriert Groß/Kleinschreibung. Kommt da ein content-type: text/html korrigiert der Apache das zu Content-Type... aber mir sind auch schon Webserver untergekommen die das nicht tun und einen fehlenden Content-Type konstatieren um dann mit Status 500 Interner Server Error die Ohren anzulegen.
    Ebenso setzen fast alle Webserver ein einfaches "\n" (LF) um zu einem "\r\n" CRLF. Und dann gibt es auc Webserver denen kann man beliebige Requestmethoden wie "ZITRONE" unterjubeln und auch bei einem "GET" einen Messagebody ohne Content-Type senden.

    Da gibt es also Einiges zu prüfen um unliebsamen Überraschungen zuvorzukommen 😉

    MFG

    PS; Diese binmode-Issues können auch vom Apache Win32 her kommen!!! Wenn ich mal viel Zeit habe untersuche ich das genauer.



  • header fields und values sind per rfc case-insensitive. jeder webserver der dir 500 wirft weil die header lower-case sind, kann einmal direkt in the muell.



  • @Cardiac sagte in Binmode STDOUT:

    header fields und values sind per rfc case-insensitive. jeder webserver der dir 500 wirft weil die header lower-case sind, kann einmal direkt in the muell.

    Ja. Es gib eben Dinge die man einfach mal so hinnehmen muss weil sie so sind 😉

    MFG



  • @_ro_ro

    um es vorweg zu nehmen: Das Problem liegt nicht in c++. Ein binmode STDOUT löst jedoch das Problem was ganz woanders liegt. Doch wo genau liegt denn nun das Problem?
    Ich habe aufgrund eines Hinweis nun einen Hexdump erstellt. Dazu pipe ich die Ausgabe eines c++Program auf ein Perlscript, also über den Weg stdout/stdin, untenstehend die c++ Source und Perl zum Nachvollziehen:

    int main(){
        for( unsigned char c = 0; c < 256; c++){
                cout << c;
        }
        return 0;
    }
    
    while ( read(STDIN, my $c, 1) ){
        printf "%02X\n", unpack "C", $c;
    }
    

    Augeführt so fw | c:\perl64\bin\perl.exe hexdump.pl | more > dump.txt und siehe da, von 0x00 bis 0xFF ist alles angekommen. C++ gibt also die Binary korrekt aus.

    Das heißt, daß der issue STDOUT auf Win32 zwischen dem CGI-Prozess und dem ApacheWin32 zustandekommt. In dieser Versuchsanordnung ändert sich nichtsam Ergebnis, wenn ich im c++Programm binmode STDOUT einschalte. Was da genau auf dem Common Gateway (CGI) passiert, entzieht sich leider meiner Kenntnis. Entscheidend jedoch ist, daß es eine Lösung gibt.

    Viele Grüße!!


Anmelden zum Antworten