多线程批量探测目标IP段的服务器类型(内网也可用)

简介:

一 原理解释

这里所说的服务器类型是指像Apache,tomcat,nginx,IIS这种。其中原理用到了HTTP Header的Responses,这里面有项叫“Server”的参数就包涵我们所需要的信息。下面是Responses的部分截图:

wKiom1ZszVDikU_EAABUcdoWcOw314.png

(PS:更多相关可自行百度“HTTP Header”)

因此,我们想要做一个多线程批量探测的软件,思路有两种:1)根据别人提供的接口然后我们去调用获取(比如:http://api.builtwith.com 这个我以后可能会写);(2)针对每个IP我们发送Get请求,然后去获取响应头文件中的Server参数

PS:文末我会放出打包好的有GUI界面的jar文件以及完整源代码

二 项目结构

这里我选择了第二种方式,自己动手做一个,虽然获取到的信息没有用接口获取的来的全。下面是整个完整小项目的目录结构:

wKioL1ZszYvSZ9IAAAAhxUJ3qCI708.png


三 核心代码

在这里核心代码在ServerTypeDemo.java这个文件中,主要是通过对指定IP以及端口发出Get请求,然后获取响应包中的“Server”,最后将结果写入文件。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package  action;
 
import  java.io.BufferedWriter;
import  java.io.IOException;
import  java.net.HttpURLConnection;
import  java.net.MalformedURLException;
import  java.net.URL;
import  java.util.List;
import  java.util.Map;
 
public  class  ServerTypeDemo{ 
     /**
      * 获取到的服务器类型写入txt
      * @param ip IP
      * @param port 提交端口
      * @param writer 写入流
     
      * @return null
      * */
     public  static  void  savaData(String ip,String port,BufferedWriter writer){
         try  {
             URL url =  new  URL( "http://"  + ip +  ":"  + port);
             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
             connection.setRequestMethod( "GET" );
             connection.setConnectTimeout( 1000 );   //毫秒
             connection.setReadTimeout( 1000 );
             Map<String, List<String>> map = connection.getHeaderFields();   //获取HTTP Header Responses
             
             List<String> server = map.get( "Server" );   //关键点
             if (server ==  null ){
                 return ;
             }
             else {  
                 //写入文件
                 for (String tmp : server){
                     writer.write(ip +  ":"  + port +  "       "  + tmp);
                     writer.newLine();                  
                 }
                 writer.flush();
                 connection.disconnect();
             }
         
         catch  (MalformedURLException e) {        
             e.printStackTrace();
         catch  (IOException e) {          
             e.printStackTrace();
         }
 
     }
     
}


四 一个陋界

wKiom1ZszdSxEenNAAB0fFaCOSw024.png

从左到右分别填:起始IP,结束IP(PS:在这里两个IP不在一个C段也行,比如:192.168.1.1~192.168.255.255),线程数,最后点击开始进行扫描,待全部线程结束后会给出提示信息。界面相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package  view;
 
import  java.awt.Dimension;
import  java.awt.FlowLayout;
import  java.awt.Font;
import  java.awt.Toolkit;
import  java.awt.event.ActionEvent;
import  java.awt.event.ActionListener;
import  java.text.Format;
import  java.text.SimpleDateFormat;
import  java.util.Date;
import  java.util.concurrent.ExecutorService;
import  java.util.concurrent.Executors;
 
import  javax.swing.JButton;
import  javax.swing.JFrame;
import  javax.swing.JMenu;
import  javax.swing.JMenuBar;
import  javax.swing.JMenuItem;
import  javax.swing.JOptionPane;
import  javax.swing.JPanel;
import  javax.swing.JTextField;
 
import  util.IPTraverse;
 
import  action.MyThread;
 
public  class  MainView  extends  JFrame  implements  ActionListener {
     /**
      * 此程序是为了批量探测目标IP段的服务器类型(Apache,tomcat,nginx,IIS。。。) 其中用到了线程池,可以自定义扫描线程数量
      * (PS:只做了一个简陋的界面 O(∩_∩)O~)
     
      * @author zifangsky
      * @blog http://www.zifangsky.cn
      * @version V1.0.0
      * @date 2015-12-9
      * */
     private  static  final  long  serialVersionUID = 1L;
     private  JPanel mainJPanel;
     private  JTextField start, end, threadNum;  // 起始IP,结束IP,线程值
     private  JButton submit;
 
     private  JMenuBar jMenuBar;
     private  JMenu help;  // 帮助
     private  JMenuItem author, contact, version, readme;  // 作者,邮箱,版本号,使用说明
 
     private  Font font =  new  Font( "宋体" , Font.LAYOUT_NO_LIMIT_CONTEXT,  16 );
 
     public  MainView() {
         super ( "批量判断服务器类型(Apache,tomcat,nginx。。。) by zifangsky" );
         Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
         screenSize = Toolkit.getDefaultToolkit().getScreenSize();  // 屏幕大小
         setPreferredSize( new  Dimension( 600 300 ));
         int  frameWidth =  this .getPreferredSize().width;  // 界面宽度
         int  frameHeight =  this .getPreferredSize().height;  // 界面高度
         setSize(frameWidth, frameHeight);
         setLocation((screenSize.width - frameWidth) /  2 ,
                 (screenSize.height - frameHeight) /  2 );
 
         mainJPanel =  new  JPanel();
         start =  new  JTextField( "192.168.1.1" 12 );
         end =  new  JTextField( "192.168.1.254" 12 );
         threadNum =  new  JTextField( "5" 8 );
         submit =  new  JButton( "开始" );
         submit.setFont(font);
 
         jMenuBar =  new  JMenuBar();
         help =  new  JMenu( "帮助" );
         help.setFont(font);
         author =  new  JMenuItem( "作者" );
         author.setFont(font);
         contact =  new  JMenuItem( "联系方式" );
         contact.setFont(font);
         version =  new  JMenuItem( "版本" );
         version.setFont(font);
         readme =  new  JMenuItem( "使用说明" );
         readme.setFont(font);
 
         mainJPanel.setLayout( new  FlowLayout(FlowLayout.CENTER,  15 40 ));
         mainJPanel.add(start);
         mainJPanel.add(end);
         mainJPanel.add(threadNum);
         mainJPanel.add(submit);
 
         jMenuBar.add(help);
         help.add(author);
         help.add(contact);
         help.add(version);
         help.add(readme);
 
         add(mainJPanel);
         setJMenuBar(jMenuBar);
         setVisible( true );
         setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
 
         submit.addActionListener( this );
         author.addActionListener( this );
         contact.addActionListener( this );
         version.addActionListener( this );
         readme.addActionListener( this );
     }
 
     public  static  void  main(String[] args) {
         new  MainView();
 
     }


五 处理点击事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
     public  void  actionPerformed(ActionEvent e) {
         if  (e.getSource() == submit) {
             Date date =  new  Date();
             Format format =  new  SimpleDateFormat( "HH_mm_ss" );
             // 结果存储的文件名
             String fileName = format.format(date) +  ".txt" ;
 
             String startIP = start.getText();
             String endIP = end.getText();
             long  sips = IPTraverse.ipToLong(startIP);
             long  eips = IPTraverse.ipToLong(endIP);
 
             int  threadNumber = Integer.valueOf(threadNum.getText());
 
             // 多线程,线程池
             ExecutorService eService = Executors.newFixedThreadPool( 50 );
             for  ( int  i =  0 ; i < threadNumber; i++) {
                 MyThread myThread =  new  MyThread(sips, eips, i, threadNumber,
                         fileName);
                 eService.execute(myThread);
             }
             eService.shutdown();
             while  ( true ) {
                 //判断是否全部线程都已经执行结束了
                 if  (eService.isTerminated()) {
                     JOptionPane.showMessageDialog( this "全部扫描结束" "提示:" ,
                             JOptionPane.INFORMATION_MESSAGE);
                     break ;
                 }
                 try  {
                     Thread.sleep( 1000 );
                 catch  (InterruptedException e1) {
                     e1.printStackTrace();
                 }
 
             }
 
         else  if  (e.getSource() == author) {
             JOptionPane.showMessageDialog( this "zifangsky" "作者:" ,
                     JOptionPane.INFORMATION_MESSAGE);
         else  if  (e.getSource() == contact) {
             JOptionPane.showMessageDialog( this ,
                     "邮箱:admin@zifangsky.cn\n博客:http://www.zifangsky.cn" ,
                     "联系方式:" , JOptionPane.INFORMATION_MESSAGE);
         else  if  (e.getSource() == version) {
             JOptionPane.showMessageDialog( this "v1.0.0" "版本号:" ,
                     JOptionPane.INFORMATION_MESSAGE);
         else  if  (e.getSource() == readme) {
             JOptionPane
                     .showMessageDialog(
                             this ,
                             "我只做了一个简陋的图像化界面,默认只扫描80和8080端口,从左到右分别填起始ip(比如:192.168.0.1)\n;"  +
                             "结束ip(比如:192.168.250.250);线程数目(别太大,不然有的结果就漏掉了)\n"  +
                             "还有就是执行的结果会保存在当前目录下的一个txt文件中" ,
                             "使用说明:" , JOptionPane.INFORMATION_MESSAGE);
         }
 
     }
 
}

在这里,由于单线程的扫描速度很慢,因此我使用了多线程。同时又为了判断全部线程是否都已经执行完毕,我又将这些线程放在了一个线程池里,通过eService.isTerminated()这个方法来判断任务是否全部执行完毕。

其实,这里还有一个关键点,如何快速的遍历一个IP段之间的每个IP?最开始我使用了笨方法(PS:四层for循环依次判断),后来度娘了一下,找到了一个不错的IP工具类,可以将IP在long和String之间相互转化。因此转化成long时,一层for循环就可以遍历了,需要String类型时再将它转化回去就可以了

IPTraverse.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package  util;
 
public  class  IPTraverse {
     /**
      * 将127.0.0.1形式的IP地址转换成十进制整数
      * @param strIp
      * @return 整数
      * */
     public  static  long  ipToLong(String strIp) {  
         long [] ip =  new  long [ 4 ];  
         // 先找到IP地址字符串中.的位置  
         int  position1 = strIp.indexOf( "." );  
         int  position2 = strIp.indexOf( "." , position1 +  1 );  
         int  position3 = strIp.indexOf( "." , position2 +  1 );  
         // 将每个.之间的字符串转换成整型  
         ip[ 0 ] = Long.parseLong(strIp.substring( 0 , position1));  
         ip[ 1 ] = Long.parseLong(strIp.substring(position1 +  1 , position2));  
         ip[ 2 ] = Long.parseLong(strIp.substring(position2 +  1 , position3));  
         ip[ 3 ] = Long.parseLong(strIp.substring(position3 +  1 ));  
         return  (ip[ 0 ] <<  24 ) + (ip[ 1 ] <<  16 ) + (ip[ 2 ] <<  8 ) + ip[ 3 ];  
    
     
     /**
      * 将十进制整数形式转换成127.0.0.1形式的ip地址  
      * @param longIp 整数型IP
      * @return 字符串型IP
      * */
     public  static  String longToIP( long  longIp) {  
         StringBuffer sb =  new  StringBuffer( "" );  
         // 直接右移24位  
         sb.append(String.valueOf((longIp >>>  24 )));  
         sb.append( "." );  
         // 将高8位置0,然后右移16位  
         sb.append(String.valueOf((longIp &  0x00FFFFFF ) >>>  16 ));  
         sb.append( "." );  
         // 将高16位置0,然后右移8位  
         sb.append(String.valueOf((longIp &  0x0000FFFF ) >>>  8 ));  
         sb.append( "." );  
         // 将高24位置0  
         sb.append(String.valueOf((longIp &  0x000000FF )));  
         return  sb.toString();  
     }  
}


六 多线程批量扫描

先将IP转化成long型数据,然后根据线程数量将这一连续的IP段均匀分给每个线程执行,再通过调用ServerTypeDemo.java这个核心类发出Get请求,最后是将获取到的信息写入到文件中

(PS:关于多线程处理IP段的原理不太理解的可以看我写的这篇文章:http://www.zifangsky.cn/2015/12/多线程循环批量处理以及多线程操作文件写入相关/

MyThread.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package  action;
 
import  java.io.BufferedWriter;
import  java.io.File;
import  java.io.FileWriter;
import  java.io.IOException;
 
import  util.IPTraverse;
 
public  class  MyThread  implements  Runnable {
     private  long  sips;  // 起始IP转化的数组
     private  long  eips;  // 结束IP转化的数组
     private  int  i;  // 第几个线程
     private  int  threadNum;  // 总共创建了几个线程
     private  String fileName;
 
     /**
      * 根据输入的数据多线程批量扫描一个IP段的服务器类型(Apache,tomcat,nginx,IIS。。。)
     
      * @param sips
      *            起始IP转化的整数
      * @param eips
      *            结束IP转化的整数
      * @param i
      *            这是第几个线程
      * @param fileName
      *            结果所保存的文件名
      * @param threadNumber
      *            扫描的线程数
     
      * @return null
      * */
     public  MyThread( long  sips,  long  eips,  int  i,  int  threadNum, String fileName) {
         this .sips = sips;
         this .eips = eips;
         this .i = i;
         this .threadNum = threadNum;
         this .fileName = fileName;
     }
 
     public  void  run() {
         try  {
             BufferedWriter writer =  new  BufferedWriter( new  FileWriter( new  File(fileName), true ));
             // 遍历每个IP
             for  ( long  step = sips + i; step <= eips; step = step + threadNum) {
                 String tempIP = IPTraverse.longToIP(step);
//              System.out.println(tempIP);
                 //这里只扫描了80和8080端口
                 ServerTypeDemo.savaData(tempIP,  "80" , writer);
                 ServerTypeDemo.savaData(tempIP,  "8080" , writer);
             }
             writer.close();
         catch  (IOException e) {
             e.printStackTrace();
         }
         
 
     }
}


七 测试

我随便找了一个IP段进行测试,结果如下:

wKiom1ZszmWyrrjrAAEoAbwgg1E026.png

好了,文章到此结束。



本文转自 pangfc 51CTO博客,原文链接:http://blog.51cto.com/983836259/1722429,如需转载请自行联系原作者

相关文章
|
2月前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
45 2
|
3月前
|
存储 缓存 应用服务中间件
|
19天前
|
存储 网络协议 网络安全
|
1月前
|
域名解析 弹性计算 安全
无法ping通ECS服务器公网IP的排查方法
无法ping通ECS服务器公网IP的排查方法
|
3月前
|
弹性计算 Ubuntu 安全
阿里云服务器镜像选择全指南:不同类型的镜像区别及选择参考
阿里云服务器镜像,作为ECS实例的“装机盘”,不仅提供了操作系统,还包含了初始化应用数据和预装软件。选择合适的镜像对于云服务器的性能和稳定性至关重要。本文将详细解析阿里云服务器提供的多种镜像类型,包括公共镜像、自定义镜像、共享镜像、云市场镜像和社区镜像,以供参考和选择。
阿里云服务器镜像选择全指南:不同类型的镜像区别及选择参考
|
3月前
|
Java
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
83 1
|
3月前
|
API Windows
揭秘网络通信的魔法:Win32多线程技术如何让服务器化身超级英雄,同时与成千上万客户端对话!
【8月更文挑战第16天】在网络编程中,客户/服务器模型让客户端向服务器发送请求并接收响应。Win32 API支持在Windows上构建此类应用。首先要初始化网络环境并通过`socket`函数创建套接字。服务器需绑定地址和端口,使用`bind`和`listen`函数准备接收连接。对每个客户端调用`accept`函数并在新线程中处理。客户端则通过`connect`建立连接,双方可通过`send`和`recv`交换数据。多线程提升服务器处理能力,确保高效响应。
54 6
|
4月前
|
弹性计算 运维 数据安全/隐私保护
云服务器 ECS产品使用问题之如何更改服务器的IP地址或端口号
云服务器ECS(Elastic Compute Service)是各大云服务商阿里云提供的一种基础云计算服务,它允许用户租用云端计算资源来部署和运行各种应用程序。以下是一个关于如何使用ECS产品的综合指南。
|
3月前
|
C语言
【C语言】多线程服务器
【C语言】多线程服务器
30 0
|
4月前
|
XML 存储 网络协议
/etc/netplan/network-manager-all.yaml 配置服务器ip
/etc/netplan/network-manager-all.yaml 配置服务器ip
181 0

热门文章

最新文章