日曜日, 9月 11, 2016

JavaとICMP

自作の自宅用メッセンジャーを作成中,Javaでネットワーク上の他のホストを検索するのにはInetAddress.isReachable()では十分ではない、という事実を今,知りました.

http://stackoverflow.com/questions/9922543/why-does-inetaddress-isreachable-return-false-when-i-can-ping-the-ip-address

仕方がないのでpingをコマンドライン経由で打つ羽目に.かなりいい加減な実装だがまあ最初のイテレーション(だけ)ではよいとする.


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Created by neko32 on 2016/09/11.
 */
public class Ping {

    private String resultCache = null;
    private static final Logger LOG = LoggerFactory.getLogger(Ping.class);

    public boolean isReachable() {
        if(resultCache == null)
            throw new IllegalStateException("run start() first");
        LOG.debug(resultCache);
        boolean decision = false;
        decision = resultCache.contains("(0%");
        if(resultCache.contains("unreachable") ||
           resultCache.contains("到達できません") ||
           resultCache.contains("timeout") ||
           resultCache.contains("タイムアウト")) {
            decision = false;
        }
        return decision;
    }

    public void start(final String destIP) throws IOException {
        final String cmd = String.format("ping %s", destIP);
        Process p = Runtime.getRuntime().exec(cmd);
        StringBuilder sb = new StringBuilder();
        try(InputStreamReader is = new InputStreamReader(p.getInputStream(), "MS932");
             BufferedReader br = new BufferedReader(is)) {
            String line = null;
            while((line = br.readLine()) != null) {
                sb.append(line);
            }
        }
        resultCache = sb.toString();
    }

}


こちらはそのユニットテスト.
mport org.scalatest.{GivenWhenThen, FeatureSpec}
import org.tanuneko.im.net.util.Ping

/**
  * Created by neko32 on 2016/09/11.
  */
class PingSpec extends FeatureSpec with GivenWhenThen {

  info("Ping is a small utility to run ping through command line.")
  info("Because InetAddress.isReachable() doesn't rely on actual ping but ECHO(TCP 7), not reliable")

  feature("Ping") {
    scenario("Ping succeeds against known ip address(local loopback)") {
      When("Ping is executed")

      val ping = new Ping
      ping.start("127.0.0.1")

      Then("Ping should succeed")
      assert(ping.isReachable)

    }
  }

  feature("Ping") {
    scenario("Ping fails against unknown ip address") {
      When("Ping is executed")

      val ping = new Ping
      ping.start("3.99.156.254")

      Then("Ping should fail")
      assert(!ping.isReachable)

    }
  }

}

0 件のコメント: