1

I want to check which IP(s) is/are available in a segment.

public class Test {
       static volatile int cnt; 
       public static void main(String[] s) throws InterruptedException{
              int i;
              for(i=1;i<256;i++){
                     PING ping = new PING(i);
                     Thread t = new Thread(ping);
                     t.start();
              }
              Thread.sleep(200);
              System.out.println("\ncnt: "+cnt);
       }

       static class PING implements Runnable{
              private int i;
              private String ip = "172.20.1.";
              private String host;
              PING(int i){
                     this.i = i;
              }

              public void run() {
                     host = ip + i;
                     try {

                           if(InetAddress.getByName(host).isReachable(200)){
                                  cnt++;
                                  System.out.print(i+", ");
                           }

                     } catch (IOException e) {
                           e.printStackTrace();
                     }
              } 
       }
}

I know there are 7 IPs available and the expected result is:

1, 2, 24, 79, 81, 254, 60,
cnt: 7

However, I got 5 or 6 IPs more frequently than 7 during my test, and sometimes I got below result(6 IPs but cnt is 5):

24, 79, 81, 2, 1, 60,
cnt: 5

Can anyone tell me the reason? Thanks in advance.

xin
  • 309
  • 2
  • 19
  • 3
    You are printing your thread result simply after 200ms rather than waiting for them all to be complete – Chris Jul 10 '17 at 14:44
  • Your main thread does not synchronize with the other threads. Also some of the threads probably do not receive answer within 200ms. – Balázs Nemes Jul 10 '17 at 14:46
  • @BalázsNemes I checked that each IP will respond within 10 ms(by `ping 172.20.1.x -w 10`). On the other hand, I change the timeout value to 2000 `isReachable(2000)` but there's no difference. And could you give some hints how to synchronize in a loop? – xin Jul 11 '17 at 02:46

3 Answers3

0

You assume that your thread will be finished within 200ms. If the server's answer takes longer, you will not see the result.

Lukas S.
  • 11
  • 2
0

You need a more reliable way to determine when your threads finish, here is a very simple check:

I created another int that keeps track of how many threads are complete and when they are all done it prints your result. (Each thread calls complete() when it is done)

public class Test {
       static volatile int cnt; 
       static volatile int finished = 0;
       public static void main(String[] s) throws InterruptedException{
              int i;
              for(i=1;i<256;i++){
                     PING ping = new PING(i);
                     Thread t = new Thread(ping);
                     t.start();
              }
       }

       public static void complete() {
           finished++;
           if(finished >= 256) {
              System.out.println("\ncnt: "+cnt);
           }
       }

       static class PING implements Runnable{
              private int i;
              private String ip = "172.20.1.";
              private String host;
              PING(int i){
                     this.i = i;
              }

              public void run() {
                     host = ip + i;
                     try {

                           if(InetAddress.getByName(host).isReachable(200)){
                                  cnt++;
                                  System.out.print(i+", ");
                           }

                     } catch (IOException e) {
                           e.printStackTrace();
                     }
                     complete();
              } 
       }
}
Chris
  • 2,435
  • 6
  • 26
  • 49
  • Thank you. But it seems no stable. I mean, it's still possible to get 5, 6 or 7 IPs by my test. I think, calling `complete()` only stores the number of executions of the loop to `finished`, but how to guarantee each thread has finished? – xin Jul 11 '17 at 03:02
  • I am unfamiliar is the specifics of `InetAddress.getByName(host).isReachable(200)` but from the [javadoc](http://download.java.net/jdk7/archive/b123/docs/api/java/net/InetAddress.html#isReachable(int)) I can't confirm if this is blocking or not - could you confirm that `isReachable` will block until it succeeds or reaches the timeout? – Chris Jul 11 '17 at 13:33
  • Also another note, you may need to increase your timeout or change your method of pinging, as noted from this question - https://stackoverflow.com/questions/9555549/java-inetaddress-isreachable-timeout – Chris Jul 11 '17 at 13:36
  • with `for(i =1;i<3;i++)` I ping 2 IPs(only one is reachable) with the same code but `try` part being changed to `try { System.out.println(Thread.currentThread().getName()+System.currentTimeMillis()); if(InetAddress.getByName(host).isReachable(2000)) { System.out.println(Thread.currentThread().getName()+System.currentTimeMillis()); } System.out.println(Thread.currentThread().getName()+System.currentTimeMillis()); }` then get `Thread-01499781381771 Thread-11499781381771 Thread-01499781381858 Thread-01499781381858 Thread-11499781383443`. – xin Jul 11 '17 at 14:06
  • So I guess it will block until it succeeds(Thread - 0) or reaches the timeout(Thread -1, but the time gap is less than 2000ms?) – xin Jul 11 '17 at 14:09
  • Well I would assume it can fail / succeed in less than 2000ms if the conditions are met. However this is a bit out of my realm of knowledge so I'm not sure I can help you much more. (No access to a computer for now) – Chris Jul 11 '17 at 14:15
0

I would suggest to use Callable<T> and Future<V> see my example below:

public class PingTest {

  static class PING implements Callable<String>{
    private int i;
    private String ip = "172.20.1.";
    private String host;
    PING(int i){
      this.i = i;
    }

    @Override
    public String call() throws Exception {
      host = ip + i;
      try {

        if(InetAddress.getByName(host).isReachable(200)){
          return  i+", ";
        }else{
          return "not reachable";
        }

      } catch (IOException e) {
        e.printStackTrace();
      }
      return "not reachable";
    }
  }


  public static void main(String[] s) throws InterruptedException, ExecutionException {

    List<Future<String>> results = new ArrayList<>();
    ExecutorService executor = Executors.newFixedThreadPool(255);
    for(int i=1;i<256;i++) {
      results.add(executor.submit(new PING(i)));
    }
    //Synchronization starts here
    int numberOfFinishedThreads;
    {
      Thread.sleep(100);
      numberOfFinishedThreads = 0;
      for(Future<String> result : results){
        if(result.isDone()){
          numberOfFinishedThreads++;
        }
      }
    }while(numberOfFinishedThreads < 255);
    //Here we are synchronized
    int numberOfReachable = 0;
    for(Future<String> result : results){
      if(! result.get().equals("not reachable")){
        System.out.print(result.get());
        numberOfReachable++;
      }
    }
    System.out.println("\ncnt: " + numberOfFinishedThreads);
  }

}

The above code is not tested, but I hope it will work :). Here you can find a good guide about Java concurency: http://winterbe.com/posts/2015/04/07/java8-concurrency-tutorial-thread-executor-examples/

Balázs Nemes
  • 699
  • 4
  • 9
  • Well, embarrassedly this is a little complicated and beyond my current knowledge scope in Java ;(. Maybe I should learn something from the link you posted first. Thanks! – xin Jul 12 '17 at 01:01