Saturday 28 July 2012

Selector と blocking mode

Java 5 から入った java.nio の機能なんだけど、socket のデータが来ているかどうかを調べようと思うと、Selector と Channel を使う。Unix の select に相当する(実際には kevent ) わけだけど。

でも、何故か、socket を non blocking に設定しないといけない。そうしないと library level で文句を言ってくる。この non blocking は、fcntl の F_SETFL/O_NONBLOCK なはず。

これは、おかしいと思うんだよな。O_NONBLOCK は、read() がデータがないと -1 を返すってやつなはず。select できるかどうかとは関係ないじゃん。

select すればデータは来ていることがわかるけど、どれくらい来ているかまではわからない。なので、read しようとすると block する可能性がある。なので、O_NONBLOCK したい場合があるのはわかる。でも、データがあるなら、1 packet は取りたいはずだよね? block してでも。

僕は普通は、

* 先頭にパケット長を入れておいて、その長さまで読む

という実装になると思う。つうか、ほとんどそうなはず。本当は Datalink 層にそういう機能があるはずだけどさ。

この問題は、TCP か UDP とも独立。

UDP は、本来 packet が受け取れるか受け取れないかどちらかのはずなので、block するはずないんだよね。UDP なら read は、1 packet 読んで戻って来るべきで、1 packet ないなら -1 を返すべきだと思う。でも、そうはならずに、read で指定された長さまで block して読むか、まったく読まないで -1 を返すということになったの? なんで、こんなことになったのか良くわからないです。

O_NONBLOCK をセットすると read で読み足りない場合の処理を書かないといけない(まぁ、書かないといけないんだけど)し、その処理は busy wait になってしまいがち。

No comments: