Vì vậy, tôi đang cố gắng để mô phỏng một số kết nối HTTP liên tục cơ bản bằng cách sử dụng ổ cắm và Ruby - cho một lớp học đại học.Làm cách nào để xử lý đúng các kết nối TCP liên tục (để mô phỏng một máy chủ HTTP)?
Vấn đề là xây dựng một máy chủ - có thể xử lý nhiều máy khách - nhận được đường dẫn tệp và trả lại nội dung tệp - giống như một HTTP GET.
Vòng lặp thực hiện máy chủ hiện tại đang lắng nghe khách hàng, kích hoạt luồng mới khi có kết nối đến và đọc đường dẫn tệp từ ổ cắm này. Nó rất câm, nhưng nó hoạt động tốt khi làm việc với các kết nối không tồn tại - một yêu cầu cho mỗi kết nối.
Nhưng chúng phải liên tục.
Điều đó có nghĩa là khách hàng không nên lo lắng về việc đóng kết nối. Trong phiên bản không liên tục, máy chủ sẽ phản hồi lại và đóng kết nối - tạm biệt ứng dụng khách, chia tay. Nhưng liên tục có nghĩa là luồng máy chủ nên lặp lại và chờ thêm các yêu cầu đến cho đến khi ... tốt cho đến khi không còn yêu cầu nào nữa. Làm thế nào để máy chủ biết điều đó? Nó không! Một số loại thời gian chờ là cần thiết. Tôi đã cố gắng làm điều đó với Timeout của Ruby, nhưng nó không hoạt động.
Googling cho một số giải pháp - ngoài việc được thông báo kỹ lưỡng để tránh sử dụng mô-đun Thời gian chờ - tôi đã thấy rất nhiều bài đăng về phương thức IO.select, nên xử lý vấn đề này. thực sự âm thanh mát mẻ, xem xét cách Ruby chủ đề (không) làm việc). Tôi đang cố gắng để hiểu ở đây như thế nào IO.select hoạt động, nhưng vẫn không thể làm cho nó hoạt động trong kịch bản hiện tại.
Vì vậy, tôi Aske về cơ bản hai điều:
làm thế nào tôi có thể có hiệu quả làm việc vấn đề thời gian chờ này trên server-side, hoặc là sử dụng một số chủ đề giải pháp dựa trên, tùy chọn ổ cắm ở mức độ thấp hoặc một số kỳ diệu IO.select ?
làm cách nào để phía máy khách biết rằng máy chủ đã đóng kết nối của máy chủ?
Dưới đây là các mã hiện tại cho máy chủ:
require 'date'
module Sockettp
class Server
def initialize(dir, port = Sockettp::DEFAULT_PORT)
@dir = dir
@port = port
end
def start
puts "Starting Sockettp server..."
puts "Serving #{@dir.yellow} on port #{@port.to_s.green}"
Socket.tcp_server_loop(@port) do |socket, client_addrinfo|
handle socket, client_addrinfo
end
end
private
def handle(socket, addrinfo)
Thread.new(socket) do |client|
log "New client connected"
begin
loop do
if client.eof?
puts "#{'-' * 100} end connection"
break
end
input = client.gets.chomp
body = content_for(input)
response = {}
if body
response.merge!({
status: 200,
body: body
})
else
response.merge!({
status: 404,
body: Sockettp::STATUSES[404]
})
end
log "#{addrinfo.ip_address} #{input} -- #{response[:status]} #{Sockettp::STATUSES[response[:status]]}".send(response[:status] == 200 ? :green : :red)
client.puts(response.to_json)
end
ensure
socket.close
end
end
end
def content_for(path)
path = File.join(@dir, path)
return File.read(path) if File.file?(path)
return Dir["#{path}/*"] if File.directory?(path)
end
def log(msg)
puts "#{Thread.current} -- #{DateTime.now.to_s} -- #{msg}"
end
end
end
Cập nhật
tôi đã có thể mô phỏng các hành vi gian chờ sử dụng phương pháp IO.select, nhưng việc thực hiện không cảm thấy tốt khi kết hợp với một vài chủ đề để chấp nhận các kết nối mới và một cặp khác để xử lý các yêu cầu. Đồng thời làm cho tình hình điên và không ổn định, và tôi có lẽ không gắn bó với nó trừ khi tôi có thể tìm ra cách tốt hơn để sử dụng giải pháp này.
Cập nhật 2
Có vẻ như Timeout vẫn là cách tốt nhất để xử lý này. Tôi gắn bó với nó cho đến khi tìm thấy một lựa chọn tốt hơn. Tôi vẫn không biết cách xử lý các kết nối máy khách zombie.
Giải pháp
tôi endend bằng cách sử dụng IO.chọn (lấy cảm hứng khi nhìn vào mã webrick). Bạn cha kiểm tra phiên bản cuối cùng here (lib/http/server/client_handler.rb)
Bạn có thể không chỉ đóng kết nối tại máy khách khi nó đã nhận được tất cả các tệp của nó và nó không còn yêu cầu để thực hiện? –
có thể giúp bạn http://stackoverflow.com/questions/6158228/how-do-i-create-persistant-tcpsockets – toch
@MartinJames Điều đó sẽ làm cho quy trình dễ dàng hơn nhiều, nhưng đặc tả HTTP nêu rõ rằng máy khách không nên t lo lắng về kết nối; đây là trách nhiệm của máy chủ. –