簡體   English   中英

使用TCPServer的Ruby中的簡單HTTP服務器

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM