2013-03-29 50 views
5

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)

+0

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? –

+0

có thể giúp bạn http://stackoverflow.com/questions/6158228/how-do-i-create-persistant-tcpsockets – toch

+0

@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ủ. –

Trả lời

0

Bạn nên thực hiện một cái gì đó như gói heartbeat.Client bên nên gửi gói đặc biệt sau vài giây/phút để đảm bảo rằng máy chủ không thời gian ra khỏi kết nối trên máy khách. Bạn chỉ cần tránh làm bất cứ điều gì trong cuộc gọi này.

Các vấn đề liên quan