recv() inkludiert unerwünschte 0x0D Chars



  • Halli hallo.

    Ich arbeite zZ an einer Methode, via Socket eine Captcha als Bild abzuspeichern.

    Als ich in meinem eigentlichen Program nicht weiter kam und dachte, es habe evtl mit meiner Klasse zu tun, die eine Socketverbindung aufbaut und sie als Stringpointer zurück gibt.

    Jetzt habe ich ein Testprogramm geschrieben, was im Endeffekt wirklich nur die Captcha requested und den Inthalt in captcha.png abespeichert.

    Diesmal habe ich ohne Pointer, cout und strings gearbeitet, also alles sehr direkt ohne dass etwas durchs Transferieren schleierhaft werden könnte.

    Sozusagen der direkteste Weg.

    Trotzdem habe ich das selbige Problem wie vorher:

    Mittem im Sourcecode tauchen auf einmal unerwünschte 0x0D Hex Zeichen auf.

    Ich glaube, wenn ich mich recht entsinne, sind das zusätzliche Umbrüche (also \r oder \n).

    Wieso er sie mit in den Code schreibt, verstehe ich nicht.

    Zudem schreibt er jedes einzelne Zeichen einzeln in die Datei, was heisst, dass es an ofstream nicht liegen kann.

    Ansonsten würde ja nach jedem Zeichen ein 0x0D Char folgen, was jedoch nicht der Fall ist.

    Nebendran habe ich Wireshark laufen lassen und den Code verglichen.

    Wireshark gibt mir den Code vollkommen korrekt aus.

    Schreibe ich diesen dann etwas um, sodass die Chunklengths und der Header aus der Datei verschwindet, kann ich das Bild auch darstellen lassen.

    Versuche ich selbiges bei dem Code, der mein Programm in die captcha.png schreibt, lässt sich das Bild nicht darstellen.

    Wieso? Weil mitten drin immer wieder Zeilenumbrüche enthalten sind, die eigentlich garnicht dahin gehören.

    Hat jemand eine Ahnung woran das liegt?

    Hier der Sourcecode meines Programs:

    #include <stdio.h>
    #include <conio.h>
    #include <winsock2.h>
    #include <windows.h>
    #include <fstream>
    
    using namespace std;
    
    #pragma comment( lib, "ws2_32.lib" )
    
    int startWinsock();
    
    int main( void )
    {
    	long f_result = 0;
    	SOCKET f_newSocket, f_conSocket;
    	SOCKADDR_IN f_sockAddress;
    	char f_buffer[102400] = { 0 };
    	ofstream f_output;
    
    	if( startWinsock() != 0 )
    		printf( "Error 0x0" );
    
    	f_newSocket = socket( AF_INET, SOCK_STREAM, 0 );
    
    	if( f_newSocket == INVALID_SOCKET )
    		printf( "Error 0x1" );
    
    	memset( &f_sockAddress, 0, sizeof( SOCKADDR_IN ) );
    
    	f_sockAddress.sin_addr.s_addr = inet_addr( "IP-ADDRESS" );
    	f_sockAddress.sin_family = AF_INET;
    	f_sockAddress.sin_port = htons( 80 );
    
    	f_conSocket = connect( f_newSocket, ( SOCKADDR* )&f_sockAddress, sizeof( SOCKADDR_IN ) );
    
    	if( f_conSocket == INVALID_SOCKET )
    		printf( "Error 0x2" );
    
    	strcpy_s( f_buffer, "GET /img.php HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n" );
    
    	f_result = send( f_newSocket, f_buffer, sizeof( f_buffer ), 0 );
    
    	if( f_result == SOCKET_ERROR )
    		printf( "Error 0x3" );	
    
    	f_result = recv( f_newSocket, f_buffer, sizeof( f_buffer ), 0 );
    
    	if( f_result == SOCKET_ERROR )
    		printf( "Error 0x4" );
    
    	f_output.open( "captcha.png", ios_base::out | ios_base::trunc );
    
    	printf( "Received chars: %i\n", f_result );
    
    	for( int i = 0; i < f_result; i++ )
    		f_output << f_buffer[i];
    
    	_getch();
    
    	return 0;
    };
    
    int startWinsock()
    {
    	WSADATA wsa;
    
    	return WSAStartup( MAKEWORD( 2, 0 ), &wsa );
    };
    

    Anschließend ein Ausschnitt meiner captcha.png:

    http://img25.imageshack.us/my.php?image=44095552.jpg

    Und letztendlich der dazugehörige Ausschnitt von Wireshark:

    http://img16.imageshack.us/my.php?image=61481755.jpg

    Ich habe übrigens auch schon versucht, sämtliche 0x0D zu entfernen.
    Leider werden dann natürlich auch alle Chars gelöscht, die zum eigentlichen Code gehören (also keine gute Idee).

    Ich hoffe mir kann jemand helfen!

    Lieben Gruß,

    paSe



  • Dein Problem ist "Transfer-Encoding: chunked". Dabei werden die Daten nicht nach dem Header "am Stück" verschickt, sondern in Chunks, die durch ihre Länge eingeleitet werden (auch in Wireshark sichtbar). Das siehst Du auch, wenn Du Dir den Auszug als Text anschaust:

    HTTP/1.1 200 OK\r\n...
    Transfer-Encoding: chunked\r\n...
    \r\n
    2029\r\n
    <2029 Bytes an Daten>
    xxx\r\n
    <xxx Bytes an Daten>
    

    Ich habe irgendwo eine Streambuffer-Klasse, die das Parsen der Chunks übernimmt und den "ungechunkten" Datenstrom herausgibt. Ich suche sie Dir später mal raus.

    Achja, ist es Absicht dass Du dem Server immer 100 KB schickst, egal wie kurz die Anfrage ist?



  • Die datei mit ios_base::binary zu öffnen wäre vielleicht auch sinnvoll.



  • Caster schrieb:

    Die datei mit ios_base::binary zu öffnen wäre vielleicht auch sinnvoll.

    Stimmt, vor allem unter Windows.



  • Mir ist schon klar, dass es chunked ist.

    Ich habe ja auch bereits erwähnt, dass ich den Sourcecode längst unchunked habe und die Header sowie die Chunklengths entfernt habe.

    Es geht mir auch nich um die 2 oder 3 Umbrüche nach den Chunks, sondern um die Umbrüche (insofern 0x0D wirklich ein Umbruch ist) mittem im Sourcecode, die nunmal bei Wireshark nicht da sind und auch im Übrigen dort gar nicht hingehören.

    Wie gesagt, mit den Chunks habe ich keine Probleme .. diese sind bereits wieder zusammengefügt.

    Zu mal es nur 2 Chunks sind, was das Debuggen sehr vereinfacht.

    Trotzdem habe ich keinen Plan.

    EDIT:

    ios_base::binary

    Damit gehts tatsächlich reibungslos.

    Vielen Dank für die Hilfe !!!

    Aber was bewirkt es, bzw. wieso macht das so einen Unterschied aus?


  • Administrator

    Hast du das HTTP-PDF nun gelesen? 😃

    Ehm, zu ios::binary :
    Dieses Flag garantiert, dass alles 1:1 übernommen wird, ohne Veränderung. Wenn ios::binary nicht gesetzt ist, dann darf die Bibliothek Änderungen durchführen. Auf Windows wird zum Beispiel aus einem \n ein \r\n . \r hat übrigens genau den Wert 0x0D 😉

    Programmierst du übrigens C++ oder C? <fstream> und die Klassen daraus sind zwar C++, aber 80-90% des restlichen Codes ist C. <stdio.h> ist zum Beispiel ein C Header, in C++ gibt es den gar nicht. Ausgaben und Umwandlungen kann man in C++ auch anders machen. Egal ob die WinAPI eine C Schnittstelle ist, man kann diese auch mit C++ Mitteln ansprechen.

    Grüssli



  • Dravere schrieb:

    Hast du das HTTP-PDF nun gelesen? 😃

    Ja. 😉
    Man will es ja auch nachvollziehen können.

    Dravere schrieb:

    Ehm, zu ios::binary :
    Dieses Flag garantiert, dass alles 1:1 übernommen wird, ohne Veränderung. Wenn ios::binary nicht gesetzt ist, dann darf die Bibliothek Änderungen durchführen.

    Achso, danke!

    Dravere schrieb:

    \r hat übrigens genau den Wert 0x0D 😉

    Lag ich ja ganz gut. 😛

    Dravere schrieb:

    Programmierst du übrigens C++ oder C? <fstream> und die Klassen daraus sind zwar C++, aber 80-90% des restlichen Codes ist C. <stdio.h> ist zum Beispiel ein C Header, in C++ gibt es den gar nicht. Ausgaben und Umwandlungen kann man in C++ auch anders machen. Egal ob die WinAPI eine C Schnittstelle ist, man kann diese auch mit C++ Mitteln ansprechen.

    Ich programmiere C++.

    Wenn man mit VSC++ eine "Vorlage" erstellt, ist in dieser eine stdafx.h inkludiert. Der Inhalt dieser Datei enthält die Standardlibraries stdio.h und tchar.h.

    Ohne stdio.h geht kein printf und ich wollte in diesem Testprogramm auf cout und Co verzichten, einfach um zu Prüfen, woran diese Veränderung des Codes lag.

    Lieber die altbewährten Commands benutzen und auf Nummer sicher gehen.

    Man weiß ja nie. 😉



  • unlimieD.paSe schrieb:

    Lieber die altbewährten Commands benutzen und auf Nummer sicher gehen.

    Lieber die C++-Mittel verwenden und auf Nummer sicher gehen. 😉

    Wenn du schon in C++ C-Header verwendest, dann auch die richtige Version. Also <cstdio> . Du brauchst dir von deiner IDE auch nichts vorschreiben zu lassen, <tchar.h> brauchst du beispielsweise kaum (gehört auch nicht zum C++-Standard). Und um meinen ersten Satz etwas mehr zu erläutern: Ich würde dir dringend empfehlen, dich mit den (üblichen) Sprach- und Bibliotheksmitteln von C++ auseinander zu setzen. Der Grund liegt einfach darin, dass viele Features aus C verbessert und durch typsichere, objektorientierte oder generell weniger fehleranfällige Pendants ersetzt wurden.


  • Administrator

    unlimieD.paSe schrieb:

    Wenn man mit VSC++ eine "Vorlage" erstellt, ist in dieser eine stdafx.h inkludiert. Der Inhalt dieser Datei enthält die Standardlibraries stdio.h und tchar.h.

    stdafx.h kann verändert werden, das ist einfach der vorkompilierte Header. Man kann ihn auch komplett abstellen, auch in den Vorlagen. Es gibt Leute, welche den gut finden, ich persönlich schalte das Teil immer ab. Ich arbeite zudem auch nur noch mit eigenen Vorlagen und nicht mehr denen von MSVS.

    unlimieD.paSe schrieb:

    Ohne stdio.h geht kein printf und ich wollte in diesem Testprogramm auf cout und Co verzichten, einfach um zu Prüfen, woran diese Veränderung des Codes lag.

    In C++ verwendet man <cstdio> für den C Header <stdio.h>. Hier findest du eine schöne Übersicht über die Header in C++:
    http://www.cplusplus.com/reference/

    unlimieD.paSe schrieb:

    Lieber die altbewährten Commands benutzen und auf Nummer sicher gehen.

    Dazu kann ich fast nur "hä?" sagen 🙂
    Was ist an std::cout nicht "altbewährt"? Da geht man sogar noch viel eher auf Nummer sich, als wenn man C Code in C++ verwendet 😉

    Grüssli



  • ...von dem Killerargument der Typsicherheit von cout ganz zu schweigen 😃

    Zu chunked: Ups, das hab ich überlesen. Sorry vielmals.



  • Ich habe irgendwo eine Streambuffer-Klasse, die das Parsen der Chunks übernimmt und den "ungechunkten" Datenstrom herausgibt. Ich suche sie Dir später mal raus.

    stellst du die auch hier ins forum?



  • Dravere schreib wenigstens Ja oder Nein. 🙂



  • proxyfoxy schrieb:

    Dravere schreib wenigstens Ja oder Nein. 🙂

    Das war aber LordJaxom...

    bb



  • Ups, da hab ich mich vertan. Danke für den Hinweis unskilled. :=)



  • LordJaxom schreib wenigstens "Ja" oder "Nein, weil ...". 😉 🙂



  • Nein, weil ich gerade bemerkt habe dass die Klasse auf die HttpReply-Klasse von der Bibliothek cxxtools (von tntnet) aufsetzt. D.h. bevor die Streambuffer-Klasse ihre Arbeit verrichten kann, muss das parsen der Header (was momentan in HttpReply geschieht) noch implementiert werden.

    Aber ich denke ich werde sie tntnet zur Verfügung stellen, vielleicht baut er sie in cxxtools ein.

    Wenn Du selbst cxxtools nutzt, kann ich die Klasse natürlich immernoch einstellen.



  • Hallo LordJaxom,

    da ich mir das ganze nur zu Lernzwecken angucken wollte spielt die externe Abhängigkeit glaub ich nicht so eine große Rolle.

    Würde mich freuen wenn du es ins Forum stellst oder an proxyfoxy@arcor.de schickst. 🙂

    Danke.


Anmelden zum Antworten