V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sodaless
V2EX  ›  Java

Android 客户端发起端口扫描,有什么高效率的办法么

  •  
  •   sodaless ·
    misakuo · 2015-12-31 11:18:36 +08:00 · 6029 次点击
    这是一个创建于 3244 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在有一个比较恶心的需求,需要客户端扫描开启了 49494 端口( PhotoShop Server )的 Host ,网络掩码是 255.255.248.0 ,一个子网 2000 多个主机,现在的策略是每 128 个 IP 分配一个线程进行扫描,先判断网络是不是可达,如果可达的话尝试和 49494 端口建立 Socket 连接,连接成功则视为该 Host 开启了 PhotoShop Server 。现在扫描一遍大概耗时 8 秒,感觉还是太慢,并且线程数过多( 16 个),有什么更好的办法么 ToT

    15 条回复    2016-01-18 09:32:46 +08:00
    shepherd
        1
    shepherd  
       2015-12-31 13:14:50 +08:00 via Android
    客户端是要把整个网络里开了端口的机器都扫出来吗?还是只有要扫到可用的 host 就行。如果是发现全部, 2000 多个机器,光 ping 都要好久,在没有辅助方法的情况下,单靠客户端去扫,是肯定要花一些时间的。如果客户端的使用环境比较固定,可以考虑在网络环境中驾一个机器负责扫,客户端只要向该机器获取列表即可。如果不是要发现全部 host ,就优化一下客户端扫描的算法,比如不要按 ip 的顺序扫,考虑做个散列算法什么的随机去扫等等。再不然,研究一下 Photoshop server 的协议,看看有没有什么广播之类的功能,在客户端上处理一下。
    sodaless
        2
    sodaless  
    OP
       2015-12-31 13:24:57 +08:00
    @shepherd 要发现全部,并且因为是园区网络, IP 地址经常变化。目前的问题是整个子网里可达的 IP 地址不多,扫描线程遇到不可达的 IP 时会等待直到达到超时时间后(目前设置了 150ms )才会继续扫描下一个 IP ,和这个端口建立的还必须是 TCP 连接,我也想看看能 PS Server 会不会发广播之类的,目前还没从文档上看到,官方的 sample 和文档也是一团糟
    wu360463231
        3
    wu360463231  
       2015-12-31 13:38:31 +08:00
    能在客户端运行多一个进程吗,可以的话直接写个 UDP 广播接收反馈的。这样每个子网 UDP 广播下就知道哪些主机可用
    sodaless
        4
    sodaless  
    OP
       2015-12-31 13:48:53 +08:00
    @wu360463231 可以多一个进程,在这里 UDP 广播该怎么用?求指教。
    TheCure
        5
    TheCure  
       2015-12-31 13:49:09 +08:00
    为什么要去检查 IP 是否可达啊,直接发个 SYN 包不就行了,反正你们也是独立 IP,一口气发 2000 个 SYN 包,然后看谁回复了 ACK 呗.

    但是这个方法需要用 raw socket 也就是你要有 root 权限,这在安卓上应该不好办.

    我的方法和 1L 一样,找台机器做 relay,机器上装个 zmap,nmap 之类的速度嗖嗖的,然后你去拿列表.

    至于 UDP 广播...园区的路由器是否支持广播都不知道,就算你能广播,也只能扫到一个路由器下的,什么?你要用组播?还是算了吧组播不支持 TCP 的,你还得保证 TCP UDP 端口都同时打开
    zbz
        6
    zbz  
       2015-12-31 14:16:39 +08:00
    创建 N 个 socket ,以非阻塞的方式分别连接到需要验证的<IP, Port>,然后等待 M 秒后检查连接是否成功。

    假设 N 是 1000 , M 是 1 ,那么一秒钟验证 1000 个 IP 毫无压力。
    sodaless
        7
    sodaless  
    OP
       2015-12-31 14:46:11 +08:00
    @zbz Excited !我去试试,只是不知道创建这么多 socket 开销会不会很大
    sodaless
        8
    sodaless  
    OP
       2015-12-31 16:25:47 +08:00
    @zbz 试了下果然效果拔群,有个小问题就是操作太快的话会报“ Host is down ”和“ No route to host ”,不知道是不是被网关给搞了
    zealot0630
        9
    zealot0630  
       2015-12-31 18:33:32 +08:00
    No route to host 是未收到 ARP 回应,很可能是 IP 根本没机器使用
    Host is down 是对面回应了 ARP ,但是没有回应 SYN ,多半是因为开了防火墙
    tobyxdd
        10
    tobyxdd  
       2015-12-31 18:38:37 +08:00
    用 nmap 不行么
    ericyl
        11
    ericyl  
       2015-12-31 20:06:21 +08:00
    我之前的做法是开启 socket 长连接,然后 UDP 循环发送消息,其他机器在接收到 UDP 消息后主动连接 socket
    mengskysama
        12
    mengskysama  
       2015-12-31 20:29:35 +08:00
    一般学校路由或者三层交换都会限制每秒新建连接数,我们这边限制比较死每个终端 200 。。
    gamexg
        13
    gamexg  
       2015-12-31 20:31:48 +08:00 via Android
    很麻烦吗?
    曾经在 vps 上 golang ,开 500 协程扫 google tls ,没发现问题啊。
    LGA1150
        14
    LGA1150  
       2015-12-31 22:22:39 +08:00
    Fing Network Tools - Discover any IP network
    sodaless
        15
    sodaless  
    OP
       2016-01-18 09:32:46 +08:00
    Hi all ,问题已经解决,和大家同步一下 solution , NIO 非阻塞式 socket 是一个挺好的办法,但在移动设备上依然不适用,我测试的安卓机器最多同时打开 1024 个连接后就会达到文件打开数的上限,即使队列式处理,主动关闭 socket 后句柄好像也不能即时释放。并且 socket channel 在 finishConnect 的时候会被阻塞,不知道是不是被路由设备限制了。最后的解决办法是使用 mDNS ,广播方式寻找,在 java 上有 JmDNS 库可以使用,在 Android API 16 以上系统有提供 NsdManager 服务,很好使,完美解决。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1714 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 16:34 · PVG 00:34 · LAX 08:34 · JFK 11:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.