Einfacher HTTP-Server in Ruby mit TCPServer

8

Für eine Schulaufgabe versuche ich einen einfachen HTTP-Server mit Ruby und der Socket-Bibliothek zu erstellen.

Im Moment kann ich es mit einem einfachen Hallo auf jede Verbindung antworten:

%Vor%

Dies funktioniert wie erwartet. Allerdings, wenn ich den Server habe, sag mir wer gerade mit

verbunden ist %Vor%

und Chromium (Browser) verwenden, um sich mit localhost:2000/ (nur einmal) zu verbinden, bekomme ich:

%Vor%

Ich nehme an, das ist Chrom, das zusätzliche Dateien anfordert, wie favicon.ico , und nicht mein Skript, das etwas Seltsames macht, also wollte ich die eingehende Anfrage untersuchen. Ich habe die Zeile resp = "Hello?" durch

ersetzt %Vor%

Und den Server neu gestartet. Ich habe die Anfrage in Chrom abgelehnt, und anstatt sie sofort zurückzubekommen, hing sie einfach. Inzwischen habe ich die Ausgabe Client: 127.0.0.1 in meiner Server-Ausgabe bekommen. Ich habe den "Stop" -Button in Chromium gedrückt, und dann ist der Server mit

abgestürzt %Vor%

Offensichtlich mache ich etwas falsch, da das erwartete Verhalten die eingehende Anfrage als Antwort zurücksendet.

Was vermisse ich?

    
Austin Hyde 24.09.2011, 15:51
quelle

1 Antwort

20

Ich weiß nicht wirklich über Chrome und die vier Verbindungen, aber ich werde versuchen, Ihre Fragen zu beantworten, wie Sie die Anfrage richtig lesen können.

Zunächst wird IO#read in diesem Fall nicht funktionieren. Laut der Dokumentation wird read ohne Parameter gelesen, bis es auf EOF trifft, aber so etwas passiert nicht. Ein Socket ist ein endloser Stream. Sie können diese Methode nicht verwenden, um die gesamte Nachricht einzulesen, da es keine "vollständige" Nachricht für den Socket gibt. Sie könnten lesen mit einer Ganzzahl wie read(100) oder etwas, aber das wird sowieso irgendwann blockieren.

Das Lesen eines Sockets unterscheidet sich grundlegend vom Lesen einer Datei. Ein Socket wird asynchron aktualisiert, völlig unabhängig von der Zeit, die Sie versuchen, es zu lesen. Wenn Sie 10 Bytes anfordern, ist es möglich, dass zu diesem Zeitpunkt im Code nur 5 Bytes verfügbar sind. Mit blocking IO wird der read(10) -Aufruf dann hängen bleiben und warten, bis 5 weitere Bytes verfügbar sind oder bis die Verbindung geschlossen wird. Dies bedeutet, dass, wenn Sie versuchen, Pakete von 10 Bytes wiederholt zu lesen, es irgendwann hängen bleibt. Eine andere Möglichkeit, einen Socket zu lesen, ist das Verwenden nicht blockierender E / A. In Ihrem Fall ist das jedoch nicht sehr wichtig, und es ist ein langes Thema für sich.

Hier ist ein Beispiel, wie Sie auf die Daten zugreifen können, indem Sie IO blockieren:

%Vor%

Die Methode gets versucht, vom Socket zu lesen, bis sie auf eine neue Zeile trifft. Dieser wird zu einem bestimmten Zeitpunkt für eine HTTP-Anfrage passieren, so dass, auch wenn die gesamte Nachricht Stück für Stück übertragen wird, gets eine einzelne Zeile von der Ausgabe zurückgeben sollte. Der line.chomp -Aufruf schneidet die letzten Zeilenumbrüche ab, wenn sie vorhanden sind. Wenn die gelesene Zeile leer ist, bedeutet dies, dass die HTTP-Header übertragen wurden und wir die Schleife sicher unterbrechen können (Sie können das natürlich in die Bedingung while setzen). Die Anfrage wird an die Konsole ausgegeben, auf der der Server gestartet wurde. Wenn Sie es wirklich zurück zum Browser senden möchten, ist die Idee die gleiche, Sie müssen nur die Zeilen anders behandeln:

%Vor%

Was die unterbrochene Pipe betrifft, tritt dieser Fehler auf, weil der Browser die Verbindung zwangsweise unterbricht, während read versucht, auf Daten zuzugreifen.

    
Andrew Radev 24.09.2011, 17:22
quelle

Tags und Links