Ubuntu Weekly Topics 2013年12月6日号 の「その他のニュース」で紹介されていた 「upstart-socket-bridgeをxinetdライクなソケット待ち受け管理機構として扱う アプリケーションの作り方 。」 が python3 で書かれていて、 同じことが ruby で実装できるのか気になったので、 IRC でちょっと助言を受けつつ移植してみました。

試した環境

  • amd64 の Ubuntu 13.10 (saucy)
  • /usr/bin/rubyruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]

ruby で試す

必須なのはソケット周りだけですが、 デバッグ用のメッセージをファイルに残すようにして 動作確認していたので、 その部分も残しています。

/tmp/test-service.rb:

 #!/usr/bin/ruby
 require 'socket'
 open("/tmp/test.log", "w") do |f|
   ENV.each do |key, value|
     f.puts "#{key}=#{value}"
   end
   begin
     serv_socket = Socket.for_fd(ENV["UPSTART_FDS"].to_i)
     client_socket, client_addrinfo = serv_socket.accept
     message = client_socket.recv(1024)
     f.puts message
     client_socket.send("I got your message: #{message}", 0)
     client_socket.close
   rescue Exception => e
     f.puts e.inspect
     f.puts e.backtrace
   end
   f.puts "finished"
 end

バグとしては for_fd の引数の to_i を忘れていたり、 send の引数が足りなかったりしました。

/etc/init/socket-test.conf:

 description "upstart-socket-bridge test"
 start on socket PROTO=inet PORT=34567 ADDR=127.0.0.1  # 34567 番ポートで待ち受け
 setuid exampleuser                                    # root ではなく exampleuser で動作
 exec /usr/bin/ruby /tmp/test-service.rb               # サービス起動

nc コマンドで接続して動作確認します。

 $ nc localhost 34567
 Hello Ruby
 I got your message: Hello Ruby

最後にテストで作成したファイルを削除しておきます。

 $ sudo rm /etc/init/socket-test.conf  # ブリッジとの接続解除
 $ rm /tmp/test-service.rb             # テストサービス削除
 $ rm /tmp/test.log                    # ログファイル削除

まとめ

python3 の socket.fromfd に相当するのは ruby だと BasicSocket.for_fd で、 BasicSocket クラスには accept がないので、 BasicSocket クラスを継承している Socket クラスの Socket#for_fd を使いました。

inetdxinetd だと標準入出力にソケットをつないでくれて、 サービスは簡単にかけるのに、 upstart だと accept して accept から返ってきたソケットを close するまでがサービス側でやらないといけないようになっていて、 ちょっと面倒に感じました。

たまたま目についたプログラムを移植してみただけで、 深追いはしていないのですが、 どういう利点があるものなのか、 調べてみるのも良いのかもしれません。

Disqus Comments

Kazuhiro NISHIYAMA

Ruby のコミッターとかやってます。 フルスタックエンジニア(って何?)かもしれません。 About znzに主なアカウントをまとめました。

znz znz


Published