2010年1月6日水曜日

【Ruby】UDPマルチキャスト送信で Errno::EADDRNOTAVAIL

Mac を Snow Leopard 化してから、UDPマルチキャスト送信時に以下のエラーが起きるようになってしまいました。

Errno::EADDRNOTAVAIL: Can't assign requested address - sendto(2)

使用しているRubyのバージョンは 1.8.7 p174。

具体的なコードは以下の通りです(簡略化してます):

require 'ipaddr'

# Multi-cast IP
ip = "224.0.0.10"
port = 9876
maddr = IPAddr.new(ip).hton + IPAddr.new('0.0.0.0').hton
# UDPソケットオブジェクトを作る
sock = UDPSocket.new
sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR,1)
sock.bind(ip, port)
sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, maddr)
# メッセージを送信
sock.send('hello', 0, ip, port).to_s


Leopard では問題なかったのになぜ??
小一時間を費やして試行錯誤した結果、マルチキャスト用のネットワークインターフェイスを指定してあげることで問題解決できることが分かりました。

改良版のコードは以下の通り:

require 'ipaddr'

# Multi-cast IP
ip = "224.0.0.10"
port = 9876
maddr = IPAddr.new(ip).hton + IPAddr.new('0.0.0.0').hton
# UDPソケットオブジェクトを作る
sock = UDPSocket.new
sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR,1)
sock.bind(ip, port)
sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, maddr)
# IFを指定(この場合はループバック)
sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_IF, IPAddr.new('127.0.0.1').hton)
# メッセージを送信
sock.send('hello', 0, ip, port).to_s


原因はよく分かりませんが、エラーメッセージから察するにネイティブコールでの問題のようですね。
差し当たりこの方法で解決できたので、Snow Leopard からの UDP Multicast で同様のエラーに遭遇された方は参考にしてみてください。

0 件のコメント:

コメントを投稿