私はソケットとRubyを使っていくつかの基本的なHTTP永続接続をシミュレートしようとしています。永続的なTCPソケット接続(HTTPサーバーをシミュレートするため)を正しく処理するにはどうしたらいいですか?
重要なのは、HTTP GETのように、ファイルパスを受け取りファイルコンテンツを返す複数のクライアントを処理できるサーバーを構築することです。
現在のサーバー実装はクライアントのリスニングをループし、接続が着信すると新しいスレッドを起動し、このソケットからファイルパスを読み取ります。それは非常に愚かですが、非常駐接続で作業する場合はうまく動作します - 接続ごとに1つの要求。
しかし、それらは永続的でなければなりません。
これは、クライアントが接続を閉じるのを心配する必要がないことを意味します。非永続バージョンでは、サーバーは応答をエコーし、接続を閉じます。さよならクライアント、別れ。 しかし、永続的であるということは、サーバスレッドはループして、より多くの要求が来るまで待つ必要があることを意味します。サーバーはそれをどのように知っていますか?それはありません!何らかの種類のタイムアウトが必要です。私はRubyのタイムアウトでそれをしようとしましたが、うまくいきませんでした。
いくつかのソリューションのためのグーグル - タイムアウトモジュールの使用を避けるように徹底的に勧告されています - 私はIO.selectメソッドに関する多くの記事を見てきました。 Rubyスレッド(動作しない方法)を考慮して、本当にクールに聞こえます。私はここでIO.selectの動作を理解しようとしていますが、現在のシナリオでは動作させることができませんでした。
私は効率的にどちらかのいくつかのスレッドベースのソリューション、低レベルのソケットオプションまたは一部IO.selectの魔法を使用して、サーバ側でこのタイムアウトの問題を働かせることができる方法:
は、だから私は基本的に二つのことアスケ?クライアント側は、サーバーが接続側を閉じていることをどのように知ることができますか?
ここでは、サーバの現在のコードです:
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
が更新
私はIO.selectメソッドを使用して、タイムアウトの挙動をシミュレートすることができましたが、実装はしていません新しい接続を受け入れるための2つのスレッドとリクエストを処理するためのもう1つのカップルを組み合わせると良い気分になります。同時実行性は状況を狂わせ、不安定にしますが、私はこの解決策を使用するより良い方法を見つけ出すことができない限り、おそらくそれに固執していません。
アップデート2
タイムアウトはまだこれを処理するための最良の方法であるように思えます。私はそれが良いオプションを見つけるまでそれに固執しています。 私はまだゾンビのクライアント接続に対処する方法がわかりません。私はIOを使ってendend
ソリューション
。select(webrickコードを見ているときに触発されました)。 here(lib/http/server/client_handler.rb)
クライアントですべてのファイルを受信しても、それ以上の要求がない場合、クライアントで接続を閉じることはできませんか? –
これはあなたを助けることができますhttp://stackoverflow.com/questions/6158228/how-do-i-create-persistant-tcpsockets – toch
@MartinJamesそれはプロセスをはるかに簡単にするだろうが、HTTP仕様では、接続について心配しないでください。これはサーバーの責任です。 –