HTTP Protokoll mhhh



  • PillePalle schrieb:

    Wenn der Buffer meinetwegen 1024 Bytes groß ist, werden dann auch immer nur 1024 Bytes pro Schleifendruchlauf übertragen?

    Wenn man recv(ConnectSocket,buf,len,0) schreibt dann wird maximal len Bytes übertragen, wenn Datei >= len Byte.

    Kann aber auch weniger sein, das wird Server-Seitig entschieden, der Server kann also auch weniger reinpacken. Wenn Datei > len Byte, dann leerst du ja auch den Puffer in einer Schleife und lässt ihn neu beschreiben, bis Datei zu ende gelesen ist:

    while(( brevc = recv (ConnectSocket, buf, sizeof(buf), 0 )) >0 ) 
    { 
     fwrite( buf, sizeof(char), brevc, fp )
    }
    

    oder:

    while(( brevc = recv (ConnectSocket, buf, sizeof(buf), 0 )) >0 ) 
    { 
    	fwrite( buf, brevc, 1, fp )
    }
    


  • Dankeschön klappt wunderbar. Nochwas: Hat jemand eine Idee wie man einfach den Header herausnehmen kann? Kann man das mit den Stringfunktionen machen? einfach nach dem ersten\n\n suchen?

    Gruß



  • 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;
    	}
    }
    

Anmelden zum Antworten