2017-03-20 6 views
1

Ich interessiere mich für die Grundprinzipien von Web-Servern, wie Apache oder Nginx, also entwickle ich jetzt meinen eigenen Server.Kann ich direkt aus der Datei in den Socket schreiben?

Wenn mein Server eine Anfrage erhält, sucht es nach einer Datei (z. B. index.html), wenn es existiert - lesen Sie den gesamten Inhalt in den Puffer (content) und schreiben Sie es in den Socket nach. Hier ist ein vereinfachter Code:

int return_file(char* content, char* fullPath) { 
    file = open(fullPath, O_RDONLY); 
    if (file > 0) { // File was found, OK 
     while ((nread = read(file, content, 2048)) > 0) {} 
     close(file); 
     return 200; 
    } 
} 

Die Frage ist ziemlich einfach: ist es möglich, zu vermeiden, Puffer und Dateiinhalt direkt an die Buchse schreiben?

Vielen Dank für alle Tipps :)

+1

ich habe es nie benutzt, so will ich nicht eine Antwort schreiben, aber einen Blick auf [ 'splice'] nehmen (https://linux.die.net/ Mann/2/Spleiß). Die Idee hier ist, eine Nullkopie-Übertragung durchzuführen, die Ihnen zumindest die Zeit des Kopierens der Dateidaten in den Benutzerbereich und dann zurück in den Kernelraum spart, bevor sie an den Socket gelangt. Sie können google mehr über Zero-Copy-Konzepte googeln, und es gibt einen informativen E-Mail-Austausch von Linus irgendwo da draußen sprechen über 'splice'. Ich rede hier von Linux, ich bin mir nicht sicher, was das Äquivalent von Microsoft oder anderen ist. – yano

+1

@yano 'splice' ist sehr cool und allgemein, aber im speziellen Fall des Sendens einer Datei an einen Socket ist' sendfile' einfacher und etwas effizienter, glaube ich. – rici

+1

@rici ah ja, ich stimme zu, einfacher sicherlich.Meine Vermutung ist, dass "sendFile" 'Spleiß 'unter der Haube verwendet (für Linux sowieso), aber ich weiß es nicht. – yano

Antwort

4

Es gibt keinen standardisierten Systemaufruf, der direkt von einer Datei in einen Socket schreiben kann.

Einige Betriebssysteme bieten jedoch einen solchen Aufruf. Zum Beispiel implementieren sowohl FreeBSD als auch Linux einen Systemaufruf, der sendfile genannt wird, aber die genauen Details unterscheiden sich zwischen den zwei Systemen. (In beiden Fällen müssen Sie den zugrunde liegenden Dateideskriptor für die Datei, nicht die FILE* Zeiger, obwohl auf diesen beiden Plattformen, die Sie fileno() verwenden können, die fd vom FILE* zu extrahieren.)

Für weitere Informationen:

+0

"Nicht portierbar" - 'fileno' existiert in POSIX.1-2001! –

+0

@Antti es ist sicher zwischen Posix-Implementierungen tragbar. Aber es ist nicht zu einer Nicht-Posix-Implementierung übertragbar. – rici

+0

aber dann sind auch keine Sockets :) OP verwendet fast sicher eine POSIX-Plattform, um diesen Code zu schreiben. –

3

Was Sie ist zu schreiben tun, um die „chunk“ Sie sofort an den Client zu lesen.

Um den Inhalt zu schreiben, MÜSSEN Sie es lesen, so können Sie nicht vermeiden, aber Sie können einen kleineren Puffer verwenden und den Inhalt schreiben, wie Sie sie lesen, die Notwendigkeit, die gesamte Datei in den Speicher zu lesen .

Zum Beispiel könnten Sie

unsigned char byte; 
// FIXME: store the return value to allow 
//  choosing the right action on error. 
// 
//  Note that `0' is not really an error. 
while (read(file, &byte, 1) > 0) { 
    if (write(client, &byte, 1) <= 0) { 
     // Handle error. 
    } 
} 

aber dann könnte unsigned char byte;unsigned char byte[A_REASONABLE_BUFFER_SIZE]; sein, die besser wäre, und Sie müssen nicht den gesamten Inhalt im Speicher zu speichern. }

0

Nein, ist es nicht. Es muss ein Zwischenspeicher vorhanden sein, den Sie zum Lesen/Schreiben der Daten verwenden.

Es gibt einen Randfall: Wenn Sie Speicherabbilddateien verwenden, kann die Region der zugeordneten Datei zum Schreiben in den Socket verwendet werden. Aber intern würde das System sowieso eine Operation zum Einlesen in den Speicherpuffer durchführen.

Verwandte Themen