RubyのIO.select を使って、TCP socketで返信がなくなったら自動でコネクションをきる方法
今までは、、
問い合わせ先で終了文字を設定して送り返すようにしていた(以下のようなメッセージが帰ってくるものとする)
Good morning!! Hello!! Good evening!! END
リクエストのレスポンスはソケットを回して終了文字が出てきたら終了というロジックだった
require 'socket' res = [] TCPSocket.open('localhost', 10001) do |sock| sock.puts @request_command sock.each{|s| break if s.chomp! == "END" # ENDが帰ってきたら処理を中止する res.push(s) } end puts res # => #Good morning!! #Hello!! #Good evening!! #END
- これでも一応問題はないが、終了文字が設定できない場合やわからない場合、またイレギュラーで帰ってこなかった場合などは、次の入力待ちプロセスに入ってアクセスが帰ってこなくなる。
これからはIO.selectを使う
singleton method IO.select (Ruby 2.1.0)
IO.selectを使えば、一定時間値が帰ってこなければ自動でコネクションをきって帰ってくるというオプションがある。
select(reads, writes = [], excepts = [], timeout = nil) -> [[IO]] | nil
- timeoutオプションに秒数を設定する
早すぎない程度に0.5秒応答がなければ、返り値を全て受け取り終えたとみなす場合は、以下のように書ける
res= [] TCPSocket.open('localhost', 10001) do |sock| sock.puts @request_command while select [sock], nil, nil, 0.5 res << sock.gets.chomp! end end puts res # => #Good morning!! #Hello!! #Good evening!! #END
これなら、レスポンスがどのような形で帰ってくるか正確にわからないときや、意図しない応答によるプロセスの停止が防げる。
epoll
今回のような小規模の場合は関係ないが、今はselectではなく、epollというシステムの方が効率がよいらしい。