Server::Starter 配下で動くサーバを Perl 以外で書く

Server::Starter の SYNOPSIS には、自分で Server::Starter 配下で実行するサーバを作る場合の例があります。

# in my_httpd
use Server::Starter qw(server_ports);
my $listen_sock = IO::Socket::INET->new(
    Proto => 'tcp',
);
$listen_sock->fdopen((values %{server_ports()})[0], 'w')
    or die "failed to bind to listening socket:$!";
while (1) {
    if (my $conn = $listen_sock->accept) {
        ...
    }
}

ところでこのサーバは Perl でなければ書けないのか? というと、そんなことはないのですね。
Server::Starter から起動された場合、環境変数 SERVER_STARTER_PORT に、Listen しているポートと、それに対応する fd (ファイルディスクリプタ) の値が入ってます。

$ start_server -p 3333 my_server

たとえばこうして起動した場合、$SERVER_STARTER_PORT="3333=4" などとなっているので、この fd の値(ここでは 4) を accept すれば Server::Starter 配下で動くサーバを書くことができます。

Ruby ならこんな感じ。

require "socket";
ss_port = ENV['SERVER_STARTER_PORT'] #= "3333=4"
port, fd = ss_port.split("=")
listen_sock = Socket.for_fd(fd.to_i)
while true
  conn, addr = listen_sock.accept
  # ...
end

C だったら conn = accept(fd, ...) ですね。

起動時に複数 port を指定した場合は、(host:port|port)=fd が ; で繋がれた値になります。

$ start_server -p 127.0.0.1:1234 -p 2345      # 127.0.0.1:1234=4;2345=5

以上、昨日の qpstudy01 で Server::Starter に興味を持たれたかたが多かったような(印象だった)ので書いてみました。