HTTP Protokoll mhhh
-
einfach nach dem ersten\n\n suchen?
Ganz genau.
-
Sorry wegen oben, war zu voreilig. Nicht \n\n sondern \r\n\r\n.
-
Ist ein bisschen schwierig so zu suchen da die Zeichen ja über mehrere Buffer verteilt sein können.
-
Ja genau. Hatte ich auch festgestellt
. Aber wenn man will geht alles

Gruß
-
Hi,
so hab mal eine provisorische Lösung, ohne mit Berücksichtigung der zerteilten Buffer, gebastelt. Nur ein Problem: Das Programm stürzt ab wenn ich es starte. Woran liegt das?
while(( brevc = recv (ConnectSocket, buf, sizeof(buf), 0 )) >0 ) { for(i=0;i<strlen(buf);i+=1) { if(buf[i]=='\n' && buf[i+1]=='\n') { begin=1; } } if(begin==1) { fwrite( buf, brevc, 1, fp ); printf("\r%0.2f MB empfangen.",((float)FileSize("tmp.txt") /1024)/1024); } }
-
Der Buffer den du von recv bekommst ist nicht 0 terminiert.
-
Und deswegen belibt das Programm stehen?
Wie kann man das lösen?
-
Kuckuck.
Ich hatte mir auch mal son Ding getippselt, das Dateien runterladen kann.
Die meisten http-header, die ich als Antwort bekam, waren <512 Byte.
Nur ganz selten mal ein Server, der einen etwas längeren Header zurückgeschickt hat.Mit dem String-Ende-Zeichen '\0' würde ich gar nicht erst anfangen.
Weder künstlich anhängen, nach suchen, oder sonstwas.
Hatte ich erst auch so und mich dann gewundert, warum es mit Bild- und Videodateien
nicht geklappt hat.Die benötigte Länge steckt ja bereits in brevc.
for( i = 0; i < brevc - 1; i++ ) // -1 weil du buf[i+1] abfragst.
-
Aber warum will dann Windows ein Problembericht senden, wenn ich das Prog starte?
-
Rüdiger sagte es bereits. Der buffer den recv liefert ist nicht nullterminiert (wie auch, es könnte ja eine Datei übertragen werden, die Nullbytes enthält*). Deshalb schlägt strlen fehl, weil es das Nullbyte gottweisswo, nur nicht in Deinem buffer sucht. Aber zum Glück liefert ja recv die benötigten Informationen als Rückgabewert.
[OT] * oder 0xFF
(SCNR) [/OT]
-
Also ich baue mir das, was von recv() kommt erstmal in einen eigenen Buffer zusammen.
An diesen Buffer wird nach jedem Aufruf von recv() zusätzlich 0 angehängt, um mit strstr(Buffer, "Content-Length") die Länge der (Binär-)Daten zu ermitteln und mit strstr(Buffer, "\r\n\r\n") nach dem Ende des Headers (=Beginn Content / =Begin (Binär-)Daten) suchen zu können.
recv() == Fehler => Schleifenabbruch
recv() == 0 => "gracefully closed" (sollte nicht vorkommen) => Schleifenabbruch
"Content-Length":
Länge Buffer >= Beginn Content + Length Content => Schleifenabbruch
kein "Content-Length":
strstr(Buffer, "\r\n0\r\n\r\n) => Ende der Nicht-Binär-Daten => Schleifenabbruch
Zusätzlich können (HTML-)Texte "chunked" aufgebaut sein.
a\r\n <- Länge des nächsten Teilstücks im hex-Format + \r\n 0123456789\r\n <- Teilstück + \r\n 8\r\n 89012345\r\n 0\r\n\r\n <- Endekennzeichen "\r\n0\r\n\r\n"
-
Dieser Thread wurde von Moderator/in Tim aus dem Forum ANSI C in das Forum Rund um die Programmierung verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Ich zeig dir mal wie ich das in C++ gemacht gemacht habe. Ist aber nicht so gut getestet. An die Funktion processChunk kannst du den Puffer den dir recv befüllt hat übergeben.
#include <iostream> #include <string> #include <cstring> #include <cassert> class LineBuffer { public: LineBuffer(std::size_t maximumLineLength) : maximumLineLength_(maximumLineLength) , isLineComplete_(false) { } std::size_t consumeChunk(const char* pBuffer, std::size_t bufferSize) { if(isLineComplete_) { return 0; } std::size_t newlineCharacterPosition; bool newlineCharacterFound = findNewlineCharacter(pBuffer, bufferSize, newlineCharacterPosition); std::size_t bytesToConsume = newlineCharacterFound ? newlineCharacterPosition + 1 : bufferSize; if(line_.length() + bytesToConsume > maximumLineLength_) { throw LineTooLongException(); } line_ += std::string(pBuffer, bytesToConsume); if(newlineCharacterFound) { isLineComplete_ = true; removeLineTerminator(); } return bytesToConsume; } bool isLineComplete() const { return isLineComplete_; } const std::string& getLine() const { return line_; } void reset() { line_.erase(); isLineComplete_ = false; } private: std::size_t getLineTerminatorLength() const { assert(isLineComplete()); assert(line_.length() >= 1 && line_[line_.length() - 1] == '\n'); if(line_.length() >= 2 && line_[line_.length() - 2] == '\r') { return 2; } else { return 1; } } void removeLineTerminator() { assert(isLineComplete()); line_.erase(line_.length() - getLineTerminatorLength(), std::string::npos); } bool findNewlineCharacter(const char* pBuffer, std::size_t bufferSize, std::size_t& newlineCharacterPosition) const { const char* pNewlineCharacter = static_cast<const char*>(std::memchr(pBuffer, '\n', bufferSize)); if(pNewlineCharacter == NULL) { return false; } else { newlineCharacterPosition = pNewlineCharacter - pBuffer; return true; } } private: std::string line_; bool isLineComplete_; const std::size_t maximumLineLength_; public: class LineTooLongException { }; }; LineBuffer lineBuffer(4096); enum State { HEADERS, BODY }; State state = HEADERS; void processLine(const std::string& line) { if(line.empty()) { state = BODY; } /*else { std::cout << "|" << line << "|" << std::endl; }*/ } std::size_t processLineChunk(const char* pBuffer, std::size_t bufferSize) { std::size_t bytesConsumed = lineBuffer.consumeChunk(pBuffer, bufferSize); if(lineBuffer.isLineComplete()) { processLine(lineBuffer.getLine()); lineBuffer.reset(); } return bytesConsumed; } std::size_t processBodyChunk(const char* pBuffer, std::size_t bufferSize) { std::cout << std::string(pBuffer, bufferSize); return bufferSize; } void processChunk(const char* pBuffer, std::size_t bufferSize) { std::size_t totalBytesConsumed = 0; while(totalBytesConsumed < bufferSize) { switch(state) { case HEADERS: totalBytesConsumed += processLineChunk(pBuffer + totalBytesConsumed, bufferSize - totalBytesConsumed); break; case BODY: totalBytesConsumed += processBodyChunk(pBuffer + totalBytesConsumed, bufferSize - totalBytesConsumed); break; } } } int main() { try { std::string input = "HTTP/1.1 200 OK\r\n" "Server: Apache\r\n" "Connection: close\r\n" "Content-Type: text/html\r\n" "\r\n" "<html>Hallo Welt</html>"; processChunk(input.data(), input.length()); } catch(LineBuffer::LineTooLongException&) { std::cout << "Line too long" << std::endl; } }