👻

Javaで使うSocketの一癖

に公開

java.net.Socketとは

java.net.Socketは指定したIPアドレスとポートに向かってソケット通信を行うクラスです。

使い方

使い方は非常に簡単で、サーバーとなる側でjava.net.ServerSocketの対象ポートのインスタンスを生成し、acceptにより接続を待ち受けるだけです。

サーバー側ソケット
    ServerSocket server = new ServerSocket(8080);
    Socket socket = server.accept();

クライアント側では対象IPアドレスとポートを指定したSocketクラスのインスタンスを生成するだけです。

クライアント側ソケット
    Socket socket = new Socket("192.168.10.10",8080);

あとはクライアント側からストリームに書き込み、サーバー側でストリームから読み込むという処理を記述するだけで、同一ネットワーク内にある別の機器へのソケット通信が可能になります。

簡単だが、癖がある

isConnected()やisClosed()は名前詐欺

java.net.SocketにはisConnected()とisClosed()というメソッドがあります。
しかし、

のです。
つまり、この2つのメソッドは現在接続が生きているかどうかは全く関与しないのです。

キープアライブも使えない

ソケット通信にはキープアライブという機能があります。
キープアライブはキープアライブパケットを送信することで、接続の維持および接続が生きているかを確認する機能です。
java.net.SocketにもsetKeepAlive(true)を設定することで、キープアライブを有効化できます・・・
が、接続断を検知できないケースがあります。(OSの設定など。)

もしかしたらJDKのバージョンや設定によって、挙動が変わるのかもしれませんが検知できずにハマった経験があります。

どのように接続断を検知するか

  • ストリームへの書き込み/ストリームからの読み込みでの、IOExceptionで検知する。
  • 応答のタイムアウトで検知する
    いずれにしても、再接続などの処理によりコードが複雑化するのは明らかです。

それでも何故ソケット通信を使ったか

プロジェクトによっては、ライセンスなどの関係でフレームワークが使えないという場合があります。
また組み込みのJavaなどの場合、

  • 筐体の性能が良いとも限らない
  • 処理待ちの時間減らしたい

などの関係で、標準ライブラリのソケットを使用する場合があると思います。
その場合はソケットを使用するケースが出てくると思うので、上記の癖に注意しましょう。

Discussion