本帖最后由 coldanimal 于 2011-05-24 04:38:34 编辑

解决方案 »

  1.   

    还从没涉足java网络应用方面的实际开发,一直停留在Demo阶段;不过你的代码我倒是有几点看法:
    第一是线程池是个单线程池,如果CPU是多核或连接过程中某个处于阻塞状态到超时,CPU资源利用率很低;
    第二是建立套接字是费时的,在call方法中连续创建两个Socket,却并没有调用connect()来连接服务器;
    第三是System.out.println是打印流,流是耗资源的,return服务器的IP+个"Timeout,failure"或"Success"就可以了,想看再去调用;
      

  2.   

    不动手无说服力(并不说我是个高手,只是想说怎么这么多人不去思考动手呢)
    我测试的一个示例也就200多微妙(双核CPU):import java.io.IOException;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.net.UnknownHostException;
    import java.util.Collection;
    import java.util.LinkedList;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;public class JPortScanner1 { public static void main(String[] args) throws InterruptedException, UnknownHostException {
    String ipHead;
            int lastPoint;
            String IP = InetAddress.getLocalHost().getHostAddress();        lastPoint = IP.lastIndexOf('.');        ipHead = IP.substring(0, ++lastPoint);        ExecutorService executor = Executors.newCachedThreadPool();
            Collection<Callable<String>> list = new LinkedList<Callable<String>>();
            long start = System.currentTimeMillis();
            for (int tail = 1; tail < 255; tail++) {
             list.add(new Task(ipHead, tail, 8081));
            }
            executor.invokeAll(list);
            executor.shutdown();
            long end = System.currentTimeMillis();
            System.out.println("All time: " + (end - start) + " milliseconds");
    }}class Task implements Callable<String> {
        String ipHead;
        int ipTail;
        int port;    public Task(String ipHead, int ipTail, int port) {
            this.ipHead = ipHead;
            this.ipTail = ipTail;
            this.port = port;
            System.out.println(ipHead + ipTail + ":" + port);
        }    public String call(){
            Socket connect = new Socket();
            try {
    connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);
     while(true){
             if(connect.isConnected()){
             //System.out.println(ipHead + ipTail + ":" + port + " success");
             break;
             }
            }
            connect.close();
    } catch (IOException e) {
    //System.out.println(ipHead + ipTail + ":" + port + " failure");
    }
            return null;
        }
    }
      

  3.   

    那行  executor.invokeAll(list);应该为
    executor.invokeAll(list, 200L, TimeUnit.MILLISECONDS);
    把connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);放入while(true)中;
      

  4.   


    我表示:代码有效,但需要修改,
    connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);
    我的无线局域网,4台机子,测试80端口(都开通),修改前只能找到自己,将100修改为1000,后,可以找到其它几个机子的80端口。
      

  5.   

    我测试是在一个局域网段,在查看我本机的一些监听端口时8081是开启的,所以猜想其他人的机子也许会同样的监听此端口,当然也并不是所得IP地址是有效的,有效IP也不一定会开启8081这个端口。再者,我也是只是稍微修改了你原来的代码,并没有什么不能理解的地方;如果你要确认某台服务器是否开启某个端口,你可以用命令telnet直接测试下。测试代码的话,你直接的把
    connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);
    修改为 connect.connect(new InetSocketAddress("sun.java.com", 80), 100);一个测试结果如下(xxx是我手动加的...):xxx.xxx.xxx.22:8081 success
    xxx.xxx.xxx.33:8081 success
    xxx.xxx.xxx.133:8081 success
    xxx.xxx.xxx.127:8081 success
    xxx.xxx.xxx.44:8081 success
    xxx.xxx.xxx.46:8081 success
    xxx.xxx.xxx.48:8081 success
    xxx.xxx.xxx.56:8081 success
    xxx.xxx.xxx.62:8081 success
    xxx.xxx.xxx.66:8081 success
    xxx.xxx.xxx.64:8081 success
    Actual executing Times : 625 millseconds
    All threads executing times : 131840 millseconds
    测试connect.connect(new InetSocketAddress("sun.java.com", 80), 100);结果:sun.java.com : 80 success
    sun.java.com : 80 success
    sun.java.com : 80 success
    sun.java.com : 80 success
    sun.java.com : 80 success
    sun.java.com : 80 success
    sun.java.com : 80 success
    sun.java.com : 80 success
    sun.java.com : 80 success
    sun.java.com : 80 success
    Actual executing Times : 344 millseconds
    All threads executing times : 44085 millseconds
    修改后的代码:import java.io.IOException;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.net.UnknownHostException;
    import java.util.Collection;
    import java.util.LinkedList;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;public class JPortScanner1 { public static void main(String[] args) throws InterruptedException, UnknownHostException, ExecutionException {
    String ipHead;
            int lastPoint;
            String IP = InetAddress.getLocalHost().getHostAddress();        lastPoint = IP.lastIndexOf('.');        ipHead = IP.substring(0, ++lastPoint);        ExecutorService executor = Executors.newCachedThreadPool();
            Collection<Callable<Long>> list = new LinkedList<Callable<Long>>();
            
            Collection<Future<Long>> taskList = null;
            for (int tail = 1; tail < 255; tail++) {
             list.add(new Task(ipHead, tail, 8081));
            }
            //executor.invokeAll(list, 1000L, TimeUnit.MILLISECONDS);
            long start = System.currentTimeMillis();
            taskList = executor.invokeAll(list);
            executor.shutdown();
            long end = System.currentTimeMillis();
            System.out.println("Actual executing Times : " + (end - start) + " millseconds");
            
            long times = 0L;
            for(Future<Long> task : taskList){
             times += task.get();
            }
            System.out.println("All threads executing times : " + times + " millseconds");
    }}class Task implements Callable<Long> {
        String ipHead;
        int ipTail;
        int port;    public Task(String ipHead, int ipTail, int port) {
            this.ipHead = ipHead;
            this.ipTail = ipTail;
            this.port = port;
            //System.out.println(ipHead + ipTail + ":" + port);
        }    public Long call(){
         long start = System.currentTimeMillis();
            Socket connect = new Socket();
            try {
             //connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100);
             connect.connect(new InetSocketAddress("sun.java.com", 80), 100);
             if(connect.isConnected()){
             //System.out.println(ipHead + ipTail + ":" + port + " success");
             System.out.println("sun.java.com : 80 success");
             }
        connect.close();
    } catch (IOException e) {
    //System.out.println(ipHead + ipTail + ":" + port + " failure");
    try {
    connect.close();
    } catch (IOException e1) {

    }
    }
    long end = System.currentTimeMillis();
            return (end - start);
        }
    }
      

  6.   

    这个估计与防火墙有关系,如果telenet xxx.xxx.xxx.xxx 80 不能执行,那就是此计算机开启了 80端口也不行。或许你的局域网真没有机子开启你想找的端口。所以找不到,楼主可以先弄两个确实开启指定端口的计算机测试一下。
      

  7.   


    我的局域网内1-254内一共大概有200台机器  但是用你的方法只能找到大概50台 另外的150台无法找到而且每次找到的机器还不太一样 但是基本都是ip从xxx.xxx.xxx.1 - xxx.xxx.xxx.100之内的50台  后面的就一直不能找到。
      

  8.   


    是不是可以把连接超时设置长一点:
    connect.connect(new InetSocketAddress(ipHead + ipTail, port), 100000);
      

  9.   


    线程池一下子搞255个线程本来就是有问题的  虽然CPU是没有问题
      

  10.   

    UDP? 怎么能保证对方收到你的信息 给你回信呢?
    TCP这种方式 好象只能一个一个连接测试,公司也有类似的需求 也没想到好办法,而且这种方式不但慢 占用资源还高。
      

  11.   

    Executors.newCachedThreadPool();创建的实际是个ThreadPoolExecutor,这里我可以肯定的说不会有255个线程;
    其实你可以直接的new ThreadPoolExecutor来指定最大线程数:
    ThreadPoolExecutor(4, 8, 1000, TimeUnit.MILLISECONDS, new BlockingQueue<Runnable>());至于说能不能上网,那是网络管理设置的问题了;再说现在测试的结果也不保证下次测试是一样的,谁知道接下来会发生什么事情;
    也许服务器本身就是个单线程响应 或 现在很忙无法响应...
      

  12.   

    50个线程没什么问题,但是50个tcp连接占用的资源就比较大了。
      

  13.   


    你打开一个ie,多打开几个不同的站点,可能就是20几个连接,QQ也不会少,要是P2P这种下载工具,就更不用说了。所以我觉得50个连接也不会太大。到少我所引用的代码在我这里测试很顺畅。当然我的局域网机子比较少。还有一个问题,一个局域网不可能每个机子都开启你所指定的端口,所以连接都不会建立,也就没有更多资源问题了。只是尝试建立连接的时间等待消耗。
      

  14.   

    其实应该和程序编写无关。楼主你现在是想要用UDP协议来测试还是TCP协议来测试呢?
    若你要用UDP基本可以群发给各个主机去测试;但在目的机器上必须要有客户端程序进行接收和回复信息。
    但你用TCP协议不可能快的;因为TCP通信协议就会复杂以及一些安全考虑(半连接处理和限制)。优点就是不需要在目的机器上安装测试程序。若你觉得多线程去发送信息的效果不理想,TCP协议群发效果也不会有太大提升。
      

  15.   


    是的  应该是UDP 用broadcast来实现  我写完把代码放出来 再结贴。
      

  16.   

    另外 TCPIP也是可以的  唯一的问题就是timeout的问题 扫描的时间太TM长了34楼很有道理
      

  17.   

    传统的TCP链接扫描是最傻一种, 而且消耗CPU资源,相应的时间还跟网络带宽资源有一定的关系。
    Java没有提供基于IP层的编程接口,无法实现TCP半开/半闭扫描,前面有提到NmapNmap提供了非常全的TCP扫描方式,基础指纹栈识别技术,通过TCP扫描来识别操作系统,进而发现
    系统漏洞,为下一步入侵系统探路。
      

  18.   


    组播通过UDP试验 无法查到TCP端口占用信息占个位置 表示关注 OYE..
      

  19.   

    你的代码可以不用线程 还有优化的余地 比如用NIO去做 代码回头放送....
      

  20.   

    package net;import java.io.IOException;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.SocketAddress;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;
    import java.util.Set;public class JPortScannerByNIO {
    public static void main(String[] args) throws IOException {
    int port = 80;
    int retry = 10;// 重试次数
    String ip = InetAddress.getLocalHost().getHostAddress();
    String ipHead = ip.substring(0, ip.lastIndexOf('.') + 1);
    Selector selector = Selector.open(); for (int tail = 60; tail < 65; tail++) {
    SocketChannel channel = SocketChannel.open(); SocketAddress address = new InetSocketAddress(ipHead + tail, port); channel.configureBlocking(false);
    channel.connect(address);
    channel.register(selector, SelectionKey.OP_CONNECT, address);// 这里你也可以用输入或者输出
    }
    while (retry-- > 0) {
    // selector.select(1000 * 5);这里可以设置超时时间
    selector.select();
    Set<SelectionKey> keys = selector.selectedKeys(); for (Iterator<SelectionKey> it = keys.iterator(); it.hasNext();) {
    SelectionKey key = it.next();
    it.remove(); if (key.isConnectable()) {
    System.err.println(key.attachment());
    key.cancel();
    }
    }
    }
    }
    }大概意思..
      

  21.   


    我是看过  2个问题
    1. 语言的问题  我需要跨平台解决方案  NMAP不是java搞的
    2. NMAP有很多的依赖  对于一个商业软件来说 这种依赖很要命
      

  22.   

    扫描端口是手段  检测到同一network内的机器是目的所以把所有机器装上broadcast就可以了  代码就不放了 简单得很TCPIP确实做不到  快速的扫描
      

  23.   

    表示关注,如果csdn里有这样的气氛,这样的好帖就好了!