2016-03-19 7 views
0

Ich muss (als Aufgabe) einen kleinen HTTP/1.0-Server in C schreiben.HTTP/1.0 Server in C, wie große Dateien an den Client senden?

Hier ist mein Problem: Ich weiß nicht, wie mit dem Fall umzugehen, in dem die vom Client angeforderte Seite sehr groß ist .

Ich dachte, dass es besser wäre, zuerst die ganze Datei zu lesen und dann die Antwort (einschließlich Statuszeile und Header) an den Client zu senden, der Hauptgrund dafür ist, dass ich den Statuscode entsprechend einstellen kann. Zum Beispiel sagen, dass, während der Server bereits gelesen hat und als String die Hälfte der Datei, die der Client will, read() scheitert. Ich würde dann weitermachen und "HTTP/1.0 500 Interner Serverfehler" als Statuszeile setzen. Das Problem mit diesem Ansatz ist, dass es zu viel Speicher benötigt, wenn die Datei groß ist (und da jede Verbindung von einem separaten Thread behandelt wird, wenn mehrere Threads Dateien mit beträchtlichen Dimensionen als String speichern würden, würde die Speicherbelegung verwendet werden) noch schlimmer werden).

Als Lösung dachte ich über das Öffnen der Datei, das Senden der Statuszeile und der Header, dann in einen Puffer eine bestimmte Menge (nicht zu groß) von Bytes lesen und iterativ senden, was im Puffer ist, bis ich gelesen habe/sendete die ganze Datei.

Dies löst das Problem, aber wieder, was ist, wenn read() schlägt fehl, während ich die Datei zur Hälfte bin? Die Client-Anfrage konnte wegen eines internen Fehlers nicht ausgeführt werden, daher wäre ein 500er Status-Code angebracht, aber ich habe bereits eine 200 OK-Nachricht über den Socket gesendet!

Wie wird dieses Problem normalerweise in HTTP-Servern behandelt?

+0

Welchen Fehler erwarten Sie, dass 'read()' auftritt, nachdem Sie 'read()' bereits erfolgreich in derselben Datei aufgerufen haben? Der einzige, den ich in der Praxis sehen kann, ist EINTR, was harmlos ist. Abhängig von Ihrer Plattform haben Sie möglicherweise auch bessere Optionen wie 'sendfile()'. – EOF

Antwort

0

Als Lösung dachte ich über das Öffnen der Datei, das Senden der Statuszeile und der Header, dann das Lesen eines Puffers in einer bestimmten Menge (nicht zu groß) von Bytes und das iterative Senden des Puffers bis Ich habe die ganze Datei gelesen/gesendet.

Das ist genau das, was Sie tun sollten. Fragen Sie die Dateigröße vorher, so dass Sie es in den Content-Length Response-Header setzen, und dann stoppen Sie Ihre Lese + Schleife senden, wenn Sie, dass viele Bytes gesendet haben.

Wenn Sie zu HTTP 1.1 wechseln können, haben Sie eine andere Option. Sie können den Header Content-Length weglassen und stattdessen einen Header Transfer-Encoding: chunked senden, und dann können Sie jeden Puffer im Format chunked senden (siehe RFC 2616 Section 3.6.1), wobei jeder Chunk seine eigene Byte-Größe angibt. Die Datenübertragung wird beendet, indem ein Abschnitt der Länge 0 gesendet wird. Damit können Sie große Datenmengen senden/streamen, ohne die Gesamtgröße im Voraus zu kennen. Diese Option ist jedoch in HTTP 1.0 nicht verfügbar.

Dies löst das Problem, aber wieder, was ist, wenn lese() fehlschlägt, während ich die Datei zur Hälfte durchgehe?

Die einzige Sache, die Sie tun können, ist, den Sockel zu schließen, um zu signalisieren, dass die Übertragung beendet ist. Wenn Sie einen Header Content-Length senden (oder im Fall von HTTP 1.1 Chunking senden Sie einen Block 0 Länge), wird der Client wissen, wenn es das richtige Ende der Datei empfangen hat, und eine vorzeitige Schließung ist ein Fehler. Aber ohne diese Informationen ist eine Socket-Schließung der einzige Weg, um das Ende der Übertragung zu signalisieren, und der Client kann nicht wissen, ob es erfolgreich oder fehlerhaft ist (HTTP 1.1 hat die Fähigkeit, unterbrochene Downloads wieder aufzunehmen, aber HTTP 1.0 nicht).

Die Clientanfrage konnte wegen eines internen Fehlers nicht ausgeführt werden, daher wäre ein 500er Statuscode angebracht, aber ich habe bereits eine 200 OK Nachricht über den Socket gesendet!

Sie können den Antwortstatus nicht ändern, nachdem Sie ihn gesendet haben. Wenn Sie jedoch dem Client mitteilen, wie er das richtige Dateiende erkennen kann, weiß er, wie ein fehlerhafter Download erkannt werden kann.

+0

Vielen Dank für Ihre Antwort! – Matteo