torutkのブログ

ソフトウェア・エンジニアのブログ

RubyでIPv6トライ

挫折しました。障壁高し。

障壁1)RubyIPv6に対応しているのか

ドキュメント化されている箇所を見出せないでいます。


Ruby開発者MLのアーカイブらしきところの議論で、Windows版については普通に入手できるRubyバイナリパッケージはIPv6非対応らしいことが判明しました(ruby-dev:34517からのスレッド)。Windows上でIPv6を使いたい人は、自分でRubyをビルドしてねということのようです。(その際、ソースの修正がいるような記述もありますが、未確認)


UNIX(Linux)についてはそこでも言及がなかったので不明です。
自宅PCのCentOS 5に含まれるruby 1.8.5では、IPv6アドレスを指定してUDPSocketのsendを呼ぶと"Address family not supported by protocol"となります。これは自分の書いたプログラムが悪いのかIPv6非対応なのか区別はつきませんが以下試したことをメモ。

require "socket"
udp = UDPSocket.open()
udp.send("HELLO", 0, "ff02::1234:1", 1234)

実行すると以下のようにエラーとなります。

sender.rb:13:in `send': Address family not supported by protocol - 
sendto(2) (Errno::EAFNOSUPPORT)
        from sender.rb:13
$ ruby --version
ruby 1.8.5 (2006-08-25) [i386-linux]

sendがIPv4/IPv6中立な処理になっていないのか、IPv6が無効なためエラーとなっているのか、ここでは分かりません(たぶん後者かなと思う)。

障壁2)Rubyのソケット通信処理はC言語ソケットAPIの知識が必要

TCP/UDPのソケット通信プログラムを書くには、上記のとおりUNIXBSDソケットAPIがそのまま出てきているので、実はC言語でのソケットAPIプログラミングの知識が前提です。


Rubyのリファレンスマニュアルも、C言語ソケットAPIの知識が前提で書かれています。例えばUDPSocket::sendの第2引数はflagsですが、これはmanでsend(2)を見てくださいというRubyリファレンスマニュアルの記述です。

send(mesg, flags[, dest_sockaddr])
send(mesg, flags, host, port)
ソケットを介してデータを送ります。flags に関しては send(2) を参照してください。connect していないソケットに対しては送り先を指定するため dest_sockaddr あるいは、host と port を指定する必要があります。実際に送ったデータの長さを返します。


上記のdest_sockaddrは、ソケットアドレス構造体(sockaddr_in)を意識した内容で、なにやら怪しげです(ソケットAPIの知識とRubyでのラップの仕方を知らないと・・・)。

マルチキャストの場合、さらにsetsockoptを使う必要があります。これも引数で指定するものはソケットAPIと同じです。

障壁3)IPv6対応のためのソケットAPIの使い方はちょっと違う

IPv4/IPv6決め打ちプログラミングにならないようにするには、昔流のソケットAPIの使い方ではなく、新しいソケットAPIの使い方が必要なので、ググって見かけるRubyのソケット通信プログラムではちょっと問題があります。このあたりの本に詳しく書かれています。

IPv6ネットワークプログラミング (network technology series)

IPv6ネットワークプログラミング (network technology series)

障壁4)これってマルチプラットフォーム

Windowsでは、BSDソケットAPIとは似て非なるWinSock APIが使われているので、Rubyからソケットを扱うときに違いが発生するかもしれません。

感想

当初Rubyでは2,3行でIPv6 UDPマルチキャスト送信が書けるのではないかと期待していたのですが、現時点ではまだそこまで至っていません。Rubyの標準ライブラリ(なのかな?)の充実が望まれるところです。

C++でのアプリケーション開発は標準ライブラリが貧弱なため多大な苦労をします。Javaはこの標準ライブラリが充実しています。Rubyでは簡潔にプログラムを書けるので将来的には期待しています。