您的位置:首页 > 编程语言 > Java开发

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

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


(PS:更多相关可自行百度“HTTP Header”)因此,我们想要做一个多线程批量探测的软件,思路有两种:(1)根据别人提供的接口然后我们去调用获取(比如:http://api.builtwith.com 这个我以后可能会写);(2)针对每个IP我们发送Get请求,然后去获取响应头文件中的Server参数PS:文末我会放出打包好的有GUI界面的jar文件以及完整源代码二 项目结构这里我选择了第二种方式,自己动手做一个,虽然获取到的信息没有用接口获取的来的全。下面是整个完整小项目的目录结构:


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

}

}

四 一个简陋界面

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

}

五 处理点击事件
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:
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:
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段进行测试,结果如下:


好了,文章到此结束。
(PS:欢迎大家访问我的个人博客网站:http://www.zifangsky.cn)附:完整源代码以及打包好的jar包下载:链接: http://down.51cto.com/data/2125949(PS:如果没有下载豆的话,可以浏览我个人博客网站上的这篇文章,文末有百度云盘的链接,传送门: href="http://www.zifangsky.cn/2015/12/%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%89%B9%E9%87%8F%E6%8E%A2%E6%B5%8B%E7%9B%AE%E6%A0%87ip%E6%AE%B5%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%B1%BB%E5%9E%8B/" target=_blank>http://www.zifangsky.cn/2015/12/多线程批量探测目标ip段的服务器类型/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息