DatagramChannel(UDP)のsetOption

小ネタ。

UDPで何かしたいときのためのDatagramChannelってクラスがあって、ソケットに対してオプションを設定したい時…

import java.net.StandardSocketOptions
import java.nio.channels.DatagramChannel
import java.net.StandardProtocolFamily

object Setopt {
  def main(args: Array[String]) = {
    val channel = DatagramChannel.open(StandardProtocolFamily.INET)
    // まず、SO_REUSEADDRを有効にするコードをここに書きたい
  }
}

そのままsetOptionという、使えそうなメソッドがあるので使います。

public abstract <T> DatagramChannel setOption(SocketOption<T> name, T value)

渡すのはSO_REUSEADDRに相当する値。

public static final SocketOption<Boolean> SO_REUSEADDR

さて、setOptionに定数を渡して…

    // SO_REUSEADDRを有効にするコード
    channel.setOption(StandardSocketOptions.SO_REUSEADDR, true)
Setopt.scala:9: error: type mismatch;
 found   : java.net.SocketOption[java.lang.Boolean]
 required: java.net.SocketOption[Any]
Note: java.lang.Boolean 

ぁぁ?型指定しろって言われてます。直そう。

    // SO_REUSEADDRを有効にするコード
    channel.setOption[Boolean](StandardSocketOptions.SO_REUSEADDR, true)
Setopt.scala:10: error: type mismatch;
 found   : java.net.SocketOption[java.lang.Boolean]
 required: java.net.SocketOption[scala.Boolean]
        channel.setOption[Boolean](StandardSocketOptions.SO_REUSEADDR, true)
                                                         ^
one error found

おう、ちゃんとJavaの型を渡せと。こりゃうっかり。

    // SO_REUSEADDRを有効にするコード
    channel.setOption[java.lang.Boolean](StandardSocketOptions.SO_REUSEADDR, true)

なんだか嫌な感じの見た目ですが、これで完成。


ところで、DatagramChannelは中のsocketがすぐ引っ張り出せるので…

    channel.socket.setReuseAddress(true)

こう書けます。呼び出し階層はひとつ増えてるものの、文字数は少ない。
しかし、せっかくChannelで包んでいて、そこに操作インターフェイスがあるのに、結局生ソケットを触るのはなんだ複雑な気分です。


Javaで試したら、型指定なしでもすんなり動くようなのですが。

import java.net.StandardSocketOptions;
import java.nio.channels.DatagramChannel;
import java.net.StandardProtocolFamily;
import java.io.*;

class SetOpt {
  public static void main(String[] args) throws IOException {
    DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET);
    channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
  }
}