[英]Simple HTTP server in Ruby using TCPServer
對於學校的作業,我試圖使用Ruby和套接字庫創建一個簡單的HTTP服務器。
現在,我可以用一個簡單的問候來響應任何連接:
require 'socket'
server = TCPServer.open 2000
puts "Listening on port 2000"
loop {
client = server.accept()
resp = "Hello?"
headers = ["HTTP/1.1 200 OK",
"Date: Tue, 14 Dec 2010 10:48:45 GMT",
"Server: Ruby",
"Content-Type: text/html; charset=iso-8859-1",
"Content-Length: #{resp.length}\r\n\r\n"].join("\r\n")
client.puts headers
client.puts resp
client.close
}
這按預期工作。 但是,當我讓服務器告訴我誰剛剛與
puts "Client: #{client.addr[2]}"
並使用Chromium(瀏覽器)連接到localhost:2000/
(僅一次),我得到:
Client: 127.0.0.1
Client: 127.0.0.1
Client: 127.0.0.1
Client: 127.0.0.1
我假設這是Chromium請求輔助文件,例如favicon.ico
,而不是我的腳本做得很奇怪,所以我想調查傳入的請求。 我替換了resp = "Hello?"
符合
resp = client.read()
並重新啟動服務器。 我對Chromium中的請求感到不滿,它沒有立即返回,而是掛了。 同時,我在服務器輸出中得到輸出Client: 127.0.0.1
。 我點擊了Chromium中的“停止”按鈕,然后服務器崩潰了
server.rb:16:in `write': Broken pipe (Errno::EPIPE)
from server.rb:16:in `puts'
from server.rb:16:in `block in <main>'
from server.rb:6:in `loop'
from server.rb:6:in `<main>'
顯然,我做錯了,因為預期的行為是將傳入的請求作為響應發送回去。
我想念什么?
我不太了解chrome和這四個連接,但是我將嘗試回答您有關如何正確讀取請求的問題。
首先, IO#read
在這種情況下不起作用。 根據該文件 , read
不帶任何參數讀取直到遇到EOF,但沒有這樣的情況發生。 套接字是一個無休止的流,您將無法使用該方法讀取整個消息,因為該套接字沒有“整個”消息。 您可以將read與一個整數一起使用,例如read(100)
東西,但是無論如何都會阻塞。
基本上,讀取套接字與讀取文件有很大不同。 套接字是異步更新的,完全獨立於您嘗試讀取它的時間。 如果您請求10個字節,則代碼中的這一點可能只有5個字節可用。 如果阻塞了 IO,則read(10)
調用將掛起,並等待直到另外5個字節可用,或者直到連接關閉。 這意味着,如果您嘗試重復讀取10個字節的數據包,則在某些時候它仍將掛起。 讀取套接字的另一種方法是使用非阻塞IO,但這在您的情況下不是很重要,它本身就是一個漫長的話題。
因此,這里有一個示例,說明如何使用阻塞IO來訪問數據:
loop {
client = server.accept
while line = client.gets
puts line.chomp
break if line =~ /^\s*$/
end
# rest of loop ...
}
gets
方法嘗試從套接字讀取,直到遇到換行符為止。 對於HTTP請求,此操作有時會發生,因此,即使整個消息是逐段傳輸的, gets
應從輸出返回一行。 如果存在,最后的換行符將被line.chomp
調用切斷。 如果讀取的行為空,則表示HTTP頭已傳輸,我們可以安全地中斷循環(當然,您可以將其置於while
條件中)。 該請求將轉儲到已啟動服務器的控制台。 如果您確實希望將其發送回瀏覽器,則想法是相同的,您只需要以不同的方式處理行即可:
loop {
client = server.accept
lines = []
while line = client.gets and line !~ /^\s*$/
lines << line.chomp
end
resp = lines.join("<br />")
headers = ["http/1.1 200 ok",
"date: tue, 14 dec 2010 10:48:45 gmt",
"server: ruby",
"content-type: text/html; charset=iso-8859-1",
"content-length: #{resp.length}\r\n\r\n"].join("\r\n")
client.puts headers # send the time to the client
client.puts resp
client.close
}
至於斷開的管道,則會發生此錯誤,因為在read
嘗試訪問數據時瀏覽器會強制斷開連接。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.