栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java实现端口扫描设计UI界面

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java实现端口扫描设计UI界面

一、前言

1.实验目的
参照superscan等端口扫描软件的运行情况,自行设计一个简单的端口扫描软件。能够根据TCP、IMCP等探测方法,设计程序对IP地址(单个IP,一段IP范围)、指定主机名的端口(部分端口,所有端口)进行扫描,以获得相关的信息。要求多线程技术实现;扫描过程中能显示扫描时间;图形化界面;异常告警窗口(如IP地址范围出界等)。
2.实验环境
电脑需要安装java虚拟机(JDK7或者JDK8),使用eclipse软件运行java程序,实现端口扫描。
3.安装说明
安装好JDK8以后,打开eclipse,新建一个package“a_scan_own”,新建一个类“OwnTCPScan”,将代码拷贝进去,并将passwd.txt文件放入“a_scan_own”内。
请注意,该代码内包含密码文件读写操作,因此需要修改OwnTCPScan.java文件的500行与1043行的代码,将“E:grade_3grade_3_codefirst_semesterJavaGrade3src”改为该package所在的位置,即可运行。
4.操作系统版本
Windows8、Windows10的32位、64位均可以运行本代码。

二、系统分析

2.1 基本要求
本课题的基本要求如下:

  1. 该端口扫描程序可以对IP地址进行扫描,可以扫描单个IP地址和一段范围内的IP地址;
  2. 该端口扫描程序可以对指定主机名的端口进行扫描,可以扫描部分端口或者所有端口;
  3. 采用多线程技术,可以由用户控制同时运行的线程数;
  4. 可以显示扫描时间和异常警告窗口(当用户输入不合法的信息时,给予提示);
  5. 实现图形化界面,界面友好、美观、可用性强。
    2.2 实验内容
    本课题实现了所有的基本要求,并附加了一部分功能,以提高用户的使用舒适度。用户使用该端口扫描设计软件的过程如下:
    用户输入用户名与密码进入主界面;
    用户可在主界面进行扫描操作和文件操作;
    扫描操作下,用户需要选择扫描方式,包括“根据IP地址扫描”和“根据主机名与端口号扫描”。其中,“根据IP地址扫描”的选项下包括“单个IP地址”和“一段IP地址”;“根据主机名与端口号扫描”的选项下包括“常用端口”和“部分端口”。用户可以点击“查看”按钮查看常用端口,也可以选择“部分端口”,输入端口范围进行扫描。
    扫描方式选择完成后,用户需要输入线程数。之后,点击“开始扫描”,扫描结果与扫描时间会自动显示在扫描结果显示框内。若点击“退出”,系统会弹出“确认退出吗?”的对话框以提醒用户。若点击“清空”,则会自动清空界面[1]。
    文件操作下,用户可以选择“修改密码”、“保存扫描结果”和“退出”。若点击“修改密码”,则会提示用户修改登录密码,保存密码的文件在该package目录下,打开之后,可以见到输入密码的密文形式。若点击“保存扫描结果”,用户可以自行选择将扫描结果保存在哪个目录下。若点击“退出”,系统会弹出“确认退出吗?”的对话框以提醒用户。
三、代码关键点

IP地址的多线程扫描
IP地址扫描采用多线程技术,以用户输入的IP地址和线程数为参数采用多线程的方式扫描IP地址,调用PingTester类实现IP地址扫描,PingTester类包含3个部分:构造函数、startPing函数、内部类PingRunner。
1.构造函数
构造函数PingTester(int fromip1,int fromip2,int fromip3,int fromip4,int toip3,int toip4),用于传递用户输入的参数起始IP地址,并生成包含所有的IP地址的linkedList,对象名为allIP。具体代码出现在OwnTCPScan.java文件的905~921行。
2.startPing函数
startPing函数用于创建一个线程池[5],使用ExecutorService类的对象进行多线程异步执行。startPing方法中声明了ExecutorService类的executor对象,并调用了该对象的executor方法,以异步的方式调用PingRunner类,执行多线程。具体代码出现在OwnTCPScan.java文件的922~943行。
3.PingRunner类
内部类PingRunner用于扫描IP地址并输出IP地址的可达性信息。PingRunner以Runnable类为接口,实现抽象方法run(),调用InetAddress类的isReachable()函数,判断该IP地址是否可达,若可达,则将结果添加到最终的扫描结果;若不可达,则不做任何操作。具体代码出现在OwnTCPScan.java文件的945~981行。

端口号的多线程扫描
根据主机和端口号的扫描采用多线程技术,以用户输入的主机名、线程数与端口范围为参数进行多线程扫描,调用scanPorts函数传递参数,scanPorts函数调用ScanMethod类实现端口的扫描。主要分为3个部分:scanPorts函数、ScanMethod类的构造函数、ScanMethod类的run函数。
1.scanPorts函数
scanPorts函数的形参包括主机名、端口范围、线程数、超时时间。scanPorts函数用于创建一个线程池,使用ExecutorService类的对象进行多线程异步执行。scanPorts函数中声明了ExecutorService类的threadPool对象,并调用了该对象的executor方法,以异步的方式调用ScanMethod类,执行多线程。具体代码出现在OwnTCPScan.java文件的818~839行。
2.ScanMethod类的构造函数
ScanMethod类同样拥有Runnable类的接口,其构造函数较为简单,仅实现传参作用。传递的参数包括主机名(或者主机IP地址)、待扫描的端口、线程数、超时时间。超时时间设置为0.8s。具体代码出现在OwnTCPScan.java文件的858~864行。
3.ScanMethod类的run函数
因为ScanMethod类拥有Runnable类的接口,因此必须实现抽象函数run()。通过主机IP地址和端口号,实例化SocketAddress类的对象socketAddress,建立套接字之后,再调用Socket类的connect函数,判断在规定的超时时间内能否连接上该端口。具体代码出现在OwnTCPScan.java文件的865~895行。

四、界面展示



运行说明

代码比较长,1000+。用户名为admin,密码为123456。password.txt中存放的是密码密文,而非登录密码的明文。初始内容是ADKIy3,只需要放在项目OwnTCPScan.java同级目录下。

五、完整代码
```java

@SuppressWarnings("serial")
public class OwnTCPScan extends Jframe implements ActionListener{

	JPanel panel1;
	//扫描类型
	JLabel choiceTip=new JLabel("请选择扫描方式:");
	protected static JRadioButton radioIp = new JRadioButton("根据IP地址扫描:");//IP地址单选按钮,默认选中IP地址
	protected static JRadioButton radioHost = new JRadioButton("根据主机名与端口号扫描:",true);//主机名单选按钮
	JLabel hostIP=new JLabel("(主机名或者主机IP地址)");

	protected static ButtonGroup group1 = new ButtonGroup();
	//IP地址扫描,十进制IP地址最多有12位,每3个一组,需要四个输入框

	protected static JRadioButton radiosingle = new JRadioButton("单个IP地址");//IP地址单选按钮,默认选中IP地址
	protected static JRadioButton radiomulti = new JRadioButton("一段IP地址",true);//主机名单选按钮
	protected static ButtonGroup group3 = new ButtonGroup();

	protected static JTextField singleip1=new JTextField("183",3);//输入扫描的起始IP地址前3位的可编辑文本框
	protected static JTextField singleip2=new JTextField("232",3);//输入起始IP地址4~6位的可编辑文本框
	protected static JTextField singleip3=new JTextField("231",3);//输入起始IP地址7~9位的输入框
	protected static JTextField singleip4=new JTextField("172",3);//输入起始IP地址10~12位的输入
	protected static JTextField fromip1=new JTextField("203",3);//输入扫描的起始IP地址前3位的可编辑文本框
	protected static JTextField fromip2=new JTextField("208",3);//输入起始IP地址4~6位的可编辑文本框
	protected static JTextField fromip3=new JTextField("40",3);//输入起始IP地址7~9位的输入框
	protected static JTextField fromip4=new JTextField("110",3);//输入起始IP地址10~12位的输入

	JLabel sPdot1 = new JLabel(".");
	JLabel sPdot2 = new JLabel(".");
	JLabel sPdot3 = new JLabel(".");//单个IP地址的分隔符,3个

	JLabel P1=new JLabel("~");//一个文本显示框
	JLabel Pdot1 = new JLabel(".");
	JLabel Pdot2 = new JLabel(".");
	JLabel Pdot3 = new JLabel(".");
	JLabel Pdot4 = new JLabel(".");//IP地址段的分隔符,4个

	protected static JTextField toip0=new JTextField("40",3);//输入扫描的结束IP地址第三部分
	protected static JTextField toip=new JTextField("130",3);//输入扫描的结束IP地址最后4位的输入框,默认前3部分相同
	//根据主机端口扫描
	protected static JTextField hostname=new JTextField("LAPTOP-J860BMB3",10);//初始状态下显示本机的主机号,输入主机名的可编辑文本框,可输入10个字符
	//分为所有端口和指定端口
	protected static JRadioButton radioAll=new JRadioButton("常用端口",true);
	JButton browser=new JButton("查看");
	protected static JRadioButton radioPart=new JRadioButton("部分端口");
	protected static ButtonGroup group2=new ButtonGroup();
	//指定端口的两个输入
	JLabel P2=new JLabel("~");
	protected static JTextField minPort=new JTextField("0",4);//输入最小端口号的输入框,规定最多4位数,默认为0
	protected static JTextField maxPort=new JTextField("1000",4);//输入最大端口的输入框,最多4位数,默认为1000
	//线程数
	JLabel THNUM=new JLabel("线程数:");
	protected static JTextField maxThread=new JTextField("10",3);//输入最大线程数量的输入框,默认为10个线程,3位数
	//定义按钮
	protected static JButton Submit = new JButton("开始扫描");
	protected static JButton Cancel = new JButton("退出");
	protected static JButton Clear=new JButton("清空");
	//扫描进度


	//扫描结果
	JLabel RST=new JLabel("扫描结果:  ");
	protected static Jtextarea Result=new Jtextarea();//显示文本,显示扫描结果
	//菜单栏
	protected static JMenu Menu0=new JMenu("文件(F)");//声明菜单项为文件
	protected static JMenuItem menu0Change=new JMenuItem("修改密码(G)");//声明文件下的子菜单项,3个
	protected static JMenuItem menu0Save=new JMenuItem("保存扫描结果(S)");
	protected static JMenuItem menu0Exit=new JMenuItem("退出(Q)");

	//主函数
	public static void main(String[] args) {
		Loginframe lf=new Loginframe();
		lf.setVisible(true);
		//		OwnTCPScan ownTCPScan=new OwnTCPScan();//创建一个对象
		//		ownTCPScan.setVisible(true);//显示该对象的界面
	}


	public OwnTCPScan(){//构造函数,在构造函数中完成布局
		super();
		JMenuBar menuBar=new JMenuBar();
		this.setTitle("Java端口扫描设计");
		this.setResizable(false);
		this.setSize(600,900);
		this.setLocationRelativeTo(this.getOwner());
		this.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);//设置主体完毕

		//初始状态
		singleip1.setEditable(false);
		singleip2.setEditable(false);
		singleip3.setEditable(false);
		singleip4.setEditable(false);
		fromip1.setEditable(false);
		fromip2.setEditable(false);
		fromip3.setEditable(false);
		fromip4.setEditable(false);
		toip0.setEditable(false);
		toip.setEditable(false);//初始情况下,这些项不可以修改
		radiosingle.setEnabled(false);
		radiomulti.setEnabled(false);//初始情况下,这些项不可以选中

		//设置界面
		this.setJMenuBar(menuBar);//menuBar添加到主界面
		menu0Change.addActionListener(this);
		Menu0.add(menu0Change);//修改密码项添加进Menu0即文件下面
		menu0Save.addActionListener(this);
		menu0Save.setEnabled(false);//一开始,是灰的,不能点
		Menu0.add(menu0Save);
		menu0Exit.addActionListener(this);//从始至终,都可以退出
		Menu0.add(menu0Exit);
		Menu0.setMnemonic('F');//设置文件的快捷键为crtl+F
		menu0Save.setMnemonic('S');//设置保存的快捷键为crtl+S
		menu0Exit.setMnemonic('Q');//设置退出的快捷键为crtl+Q
		menu0Change.setMnemonic('G');//设置更改密码的快捷键为crtl+G
		menu0Change.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G,InputEvent.CTRL_MASK));
		menu0Save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,InputEvent.CTRL_MASK));
		menu0Exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,InputEvent.CTRL_MASK));
		menuBar.add(Menu0);//菜单栏建立完成

		panel1 = new JPanel();
		JScrollPane scroll = new JScrollPane(Result);
		scroll.setPreferredSize(new Dimension(600,480));
		Container pane = getContentPane();
		getContentPane().add(panel1);
		getContentPane().add(Result);
		panel1.setPreferredSize(new Dimension(600, 420));
		panel1.setLayout(null);//采用无布局方式添加控件

		choiceTip.setBounds(30,30,100,20);
		panel1.add(choiceTip);
		group1.add(radioIp);
		group1.add(radioHost);
		radioIp.setBounds(30,60,200,20);
		panel1.add(radioIp);
		radioHost.setBounds(30,150,200,20);
		panel1.add(radioHost);

		group3.add(radiosingle);
		group3.add(radiomulti);
		radiosingle.setBounds(60,90,100,20);
		panel1.add(radiosingle);
		singleip1.setBounds(160,90,35,20);
		panel1.add(singleip1);
		sPdot1.setBounds(195,95,10,10);
		panel1.add(sPdot1);
		singleip2.setBounds(205,90,35,20);
		panel1.add(singleip2);
		sPdot2.setBounds(240,95,10,10);
		panel1.add(sPdot2);
		singleip3.setBounds(250,90,35,20);
		panel1.add(singleip3);
		sPdot3.setBounds(285,95,10,10);
		panel1.add(sPdot3);
		singleip4.setBounds(295,90,35,20);
		panel1.add(singleip4);//单个IP地址的输入设计完成

		radiomulti.setBounds(60,120,100,20);
		panel1.add(radiomulti);

		fromip1.setBounds(160,120,35,20);
		panel1.add(fromip1);
		Pdot1.setBounds(195,125,10,10);
		panel1.add(Pdot1);
		fromip2.setBounds(205,120,35,20);
		panel1.add(fromip2);
		Pdot2.setBounds(240,125,10,10);
		panel1.add(Pdot2);
		fromip3.setBounds(250,120,35,20);
		panel1.add(fromip3);
		Pdot3.setBounds(285,125,10,10);
		panel1.add(Pdot3);
		fromip4.setBounds(295,120,35,20);
		panel1.add(fromip4);
		P1.setBounds(330,120,10,20);
		panel1.add(P1);
		toip0.setBounds(340,120,35,20);
		panel1.add(toip0);
		Pdot4.setBounds(375,125,10,10);
		panel1.add(Pdot4);
		toip.setBounds(385,120,35,20);
		panel1.add(toip);//一段IP地址设计完成

		hostname.setBounds(230,150,150,20);
		panel1.add(hostname);
		hostIP.setBounds(380,150,150,15);
		panel1.add(hostIP);
		group2.add(radioAll);
		group2.add(radioPart);
		radioAll.setBounds(60,180,120,20);
		panel1.add(radioAll);
		browser.setBounds(180,180,60,20);
		panel1.add(browser);
		browser.setFont(new Font("",Font.BOLD,12));
		//常用端口设计完成
		radioPart.setBounds(60,210,120,20);
		panel1.add(radioPart);
		minPort.setBounds(180,210,40,20);
		panel1.add(minPort);
		P2.setBounds(220,210,10,20);
		panel1.add(P2);
		maxPort.setBounds(230,210,40,20);//指定端口设计完成
		panel1.add(maxPort);
		THNUM.setBounds(30,240,60,20);
		panel1.add(THNUM);
		maxThread.setBounds(90,240,60,20);
		panel1.add(maxThread);//线程数设计完成

		Submit.setBounds(80,290,120,30);
		panel1.add(Submit);
		Cancel.setBounds(240,290,120,30);
		panel1.add(Cancel);
		Clear.setBounds(400,290,120,30);
		panel1.add(Clear);//三个按钮设计完成
		RST.setBounds(30,350,120,20);
		panel1.add(RST);//扫描结果提示语句设计完成,至此,panel1建立完成

		pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));//下面是滚动条,即结果显示区域
		Result.setLayout(null);
		scroll.setViewportView(Result);
		scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		pane.add(scroll);
		Result.setEditable(true);//结果显示区域可编辑
		Result.setTabSize(10);
		Result.setLineWrap(true);//激活自动换行功能
		Result.setWrapStyleWord(true);//激活断行不断字功能
		Result.setBounds(40,420,500,200);
		Result.setFont(new Font("宋体",Font.BOLD,14));//面板建立完成

		//按钮的监听事件

		//两组单选按钮需要互斥,因此设置监听事件
		radioIp.addItemListener(new ItemListener() {//Host的三个项都不可以修改
			@Override
			public void itemStateChanged(ItemEvent arg0) {
				if(arg0.getSource()==radioIp){
					fromip1.setEditable(true);
					fromip2.setEditable(true);
					fromip3.setEditable(true);
					fromip4.setEditable(true);
					toip.setEditable(true);
					toip0.setEditable(true);
					singleip1.setEditable(true);
					singleip2.setEditable(true);
					singleip3.setEditable(true);
					singleip4.setEditable(true);//IP下,这些项可以修改

					radiosingle.setEnabled(true);
					radiomulti.setEnabled(true);//IP下,可以选中

					hostname.setEditable(false);
					minPort.setEditable(false);
					maxPort.setEditable(false);//IP下,这三项不可以修改

					radioAll.setEnabled(false);
					radioPart.setEnabled(false);
				}
			}
		});

		radioHost.addItemListener(new ItemListener() {

			@Override
			public void itemStateChanged(ItemEvent arg0) {
				if(arg0.getSource()==radioHost){
					OwnTCPScan.maxThread.setText("10");
					fromip1.setEditable(false);
					fromip2.setEditable(false);
					fromip3.setEditable(false);
					fromip4.setEditable(false);
					toip.setEditable(false);
					toip0.setEditable(false);
					singleip1.setEditable(false);
					singleip2.setEditable(false);
					singleip3.setEditable(false);
					singleip4.setEditable(false);//Host下,不可以修改
					radiosingle.setEnabled(false);
					radiomulti.setEnabled(false);//host下,不可以选中


					hostname.setEditable(true);
					minPort.setEditable(true);
					maxPort.setEditable(true);//Host下,这三项恢复修改
					radioAll.setEnabled(true);
					radioPart.setEnabled(true);
				}

			}
		});

		radiosingle.addItemListener(new ItemListener() {//选择单个IP地址,默认状态,不可修改IP范围下的输入
			@Override
			public void itemStateChanged(ItemEvent arg0) {
				OwnTCPScan.maxThread.setText("1");
				fromip1.setEditable(false);
				fromip2.setEditable(false);
				fromip3.setEditable(false);
				fromip4.setEditable(false);
				toip.setEditable(false);
				toip0.setEditable(false);
				singleip1.setEditable(true);
				singleip2.setEditable(true);
				singleip3.setEditable(true);
				singleip4.setEditable(true);
			}
		});

		radiomulti.addItemListener(new ItemListener() {//选中IP范围下,不可修改单个IP的输入
			@Override
			public void itemStateChanged(ItemEvent arg0) {
				OwnTCPScan.maxThread.setText("10");
				fromip1.setEditable(true);
				fromip2.setEditable(true);
				fromip3.setEditable(true);
				fromip4.setEditable(true);
				toip.setEditable(true);
				toip0.setEditable(true);
				singleip1.setEditable(false);
				singleip2.setEditable(false);
				singleip3.setEditable(false);
				singleip4.setEditable(false);
			}
		});

		radioAll.addItemListener(new ItemListener() {//选择常用端口,最小最大不可编辑

			@Override
			public void itemStateChanged(ItemEvent arg0) {

				minPort.setEditable(false);
				maxPort.setEditable(false);

			}
		});

		radioPart.addItemListener(new ItemListener() {

			@Override
			public void itemStateChanged(ItemEvent arg0) {

				minPort.setEditable(true);
				maxPort.setEditable(true);

			}
		});

		browser.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				JOptionPane.showMessageDialog(null, "常用端口包括:n21, 22, 23, 25, 26, 53,69, 80, 110, 143,443,465,69,161,162,rn" +
								"							135,995,1080,1158,1433,1521,2100, 3128, 3306, 3389,7001, 8080,rn" +
								"							8081, 9080, 9090, 43958 ,135,445,1025,1026,1027,1028,1055,5357",
						"查看常用端口", JOptionPane.INFORMATION_MESSAGE);
			}
		});

		Submit.addActionListener(new ActionListener() {//开始扫描的点击事件,调用一个类

			@Override
			public void actionPerformed(ActionEvent arg0) {
				SubmitAction submitAction=new SubmitAction();
				submitAction.actionPerformed(arg0);

			}
		});//扫描按钮的实现,是最重要的部分,里面包含合法性判别与扫描过程

		Cancel.addActionListener(new ActionListener() {//取消按钮的实现,直接退出,调用exitDialog()函数
			@Override
			public void actionPerformed(ActionEvent arg0) {
				exitDialog();//调用退出对话框函数
			}
		});

		Clear.addActionListener(new ActionListener() {//清空按钮的实现,将界面完全清空

			@Override
			public void actionPerformed(ActionEvent arg0) {
				radioIp.setSelected(false);
				radioHost.setSelected(true);
				radioAll.setSelected(true);
				singleip1.setText("");
				singleip2.setText("");
				singleip3.setText("");
				singleip4.setText("");
				fromip1.setText("");
				fromip2.setText("");
				fromip3.setText("");
				fromip4.setText("");
				toip.setText("");
				toip0.setText("");
				hostname.setText("");
				minPort.setText("");
				maxPort.setText("");
				maxThread.setText("");
				Result.setText("");

			}
		});

	}

	//菜单选项的3个点击事件
	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource()==menu0Save){
			menu0Save.setEnabled(true);
			JFileChooser fc=new JFileChooser();
			int returnVal=fc.showSaveDialog(null);
			//点击“保存”
			if(returnVal == 0){
				File saveFile=fc.getSelectedFile();
				try {
					FileWriter writeOut = new FileWriter(saveFile);
					writeOut.write(OwnTCPScan.Result.getText());
					writeOut.close();
				}
				catch (IOException ex) {
					ex.printStackTrace();
					System.out.println("保存失败");
				}
			}
			//点击“取消”
			else return;
			JOptionPane.showMessageDialog(null, "您已经成功保存数据","保存", JOptionPane.INFORMATION_MESSAGE);
		}
		if(e.getSource()==menu0Change){
			String s=JOptionPane.showInputDialog(null, "请输入新密码:", "修改密码", JOptionPane.PLAIN_MESSAGE);
			if(s==null)
				return;
			s=s.trim();
			if(s.length()==0){
				JOptionPane.showMessageDialog(null, "密码不能为空!", "修改密码", JOptionPane.ERROR_MESSAGE);
				return;
			}
			String clearText = 	"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
			String cipherText=	"UADKIy3FxgVkl5iZzWuGd1HNhOCtvjJ2pEn6Yw7PqrcQReB8Mfm0STsLX9a4ob";
			String resultText=		"";
			for(int i=0;i255||ip2<0 || ip2>255||ip3<0 || ip3>255||ipstart<0 || ipstart>255 ||ipend<0 || ipend>255 ||ipend0<0 || ipend0>255){
						noteDialog("IP地址必须是0~255之间的整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}
					//判断from是否比to要小
					if(ip3>ipend0) {
						noteDialog("起始扫描地址要小于终止扫描地址!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}
					if(ip3==ipend0&&ipstart>ipend) {
						noteDialog("起始扫描地址要小于终止扫描地址!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}

					if(maxThread<1 || maxThread>MAXTHREAD){//判断线程数量的有效范围判断条件:大于1且小于200
						noteDialog("线程数为1-"+MAXTHREAD+"之间的整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}//有效性判断完成,是符合条件的数

					else{//说明上面6个IP地址都对,且线程数正确,开始扫描IP地址,调用PingTester类,所有的内容都在这个类中
						OwnTCPScan.Result.append("线程数 "+OwnTCPScan.maxThread.getText()+"n");
						PingTester tester = new PingTester(ip1,ip2,ip3,ipstart,ipend0,ipend);
						tester.startPing(maxThread);//读进来的最大线程数
						OwnTCPScan.Submit.setEnabled(true);//允许重新扫描
						OwnTCPScan.menu0Save.setEnabled(true);//允许保存
						endTime=System.currentTimeMillis(); //获取结束时间
						System.out.println("扫描时长为:"+(double)(endTime-startTime)/1000+"s");
						OwnTCPScan.Result.append("扫描时长为:"+(double)(endTime-startTime)/1000+"sn");
					}//执行结束
				}//一段IP地址的扫描结束

				if(OwnTCPScan.radiosingle.isSelected()){//选择单个IP地址扫描
					try{//判断IP的前3位是否为int型
						sip1=Integer.parseInt(OwnTCPScan.singleip1.getText().trim());
					}
					catch(NumberFormatException e){
						noteDialog("起始IP地址的第一部分必须存在,且为整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}

					try{//判断IP的4~6位是否为int型
						sip2=Integer.parseInt(OwnTCPScan.singleip2.getText().trim());
					}
					catch(NumberFormatException e){
						noteDialog("起始IP地址的第二部分必须存在,且为整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}

					try{//判断IP的7~9位是否为int型
						sip3=Integer.parseInt(OwnTCPScan.singleip3.getText().trim());
					}
					catch(NumberFormatException e){
						noteDialog("起始IP地址的第三部分必须存在,且为整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}

					try{//判断IP的最后4位是否为int型
						sip4=Integer.parseInt(OwnTCPScan.singleip4.getText().trim());
					}
					catch(NumberFormatException e){
						noteDialog("起始IP地址的第四部分必须存在,且为整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}
					try{//判断进程数的有效性,这个不变
						maxThread=Integer.parseInt(OwnTCPScan.maxThread.getText().trim());
					}
					catch(NumberFormatException e){
						noteDialog("线程数必须存在,并且是整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}//输入合法性判断结束,是整数

					//判断条件:大于0且小于等于255
					if(sip1<0 || sip1>255||sip2<0 || sip2>255||sip3<0 || sip3>255||sip4<0 ||sip4>255){
						noteDialog("IP地址必须是0~255之间的整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}

					if(maxThread<1 || maxThread>MAXTHREAD){//判断线程数量的有效范围判断条件:大于1且小于200
						noteDialog("线程数为1-"+MAXTHREAD+"之间的整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}//输入有效性判断结束,是符合条件的数
					else{//说明上面4个IP地址都对,且线程数正确,开始扫描IP地址
						OwnTCPScan.Result.append("线程数 "+OwnTCPScan.maxThread.getText()+"n");
						PingTester tester = new PingTester(sip1,sip2,sip3,sip4,sip3,sip4);
						tester.startPing(maxThread);//读进来的最大线程数
						OwnTCPScan.Submit.setEnabled(true);
						OwnTCPScan.menu0Save.setEnabled(true);
						endTime=System.currentTimeMillis(); //获取结束时间
						System.out.println("扫描时长为:"+(double)(endTime-startTime)/1000+"s");
						OwnTCPScan.Result.append("扫描时长为:"+(double)(endTime-startTime)/1000+"sn");
					}
				}//单个IP地址扫描结束
			}//根据IP地址扫描结束,最外层结束


			if(OwnTCPScan.radioHost.isSelected()){//根据主机名进行端口扫描
				try{//判断主机名称的有效性
					@SuppressWarnings("unused")
					InetAddress ia=InetAddress.getByName(OwnTCPScan.hostname.getText().trim());
				}
				catch(UnknownHostException e){
					noteDialog("主机名无效,网络不可达!");
					OwnTCPScan.Submit.setEnabled(true);
					return;
				}

				try{//判断线程数的有效性,整数
					maxThread=Integer.parseInt(OwnTCPScan.maxThread.getText().trim());
				}
				catch(NumberFormatException e){
					noteDialog("线程数必须存在,并且是整数!");
					OwnTCPScan.Submit.setEnabled(true);
					return;
				}
				if(maxThread<1 || maxThread>MAXTHREAD){//判断线程数量的有效范围判断条件:大于1且小于200
					noteDialog("线程数为1-"+MAXTHREAD+"之间的整数!");
					OwnTCPScan.Submit.setEnabled(true);
					return;
				}//常用端口的有效性判断完成

				if(OwnTCPScan.radioAll.isSelected()){//判断选中的常用端口还是指定端口
					//很简单,直接进行扫描端口
					hostname=OwnTCPScan.hostname.getText();
					List portList = new linkedList();// 定义一个List容器表示扫描的端口的List集合
					//之所以选择linkedList,因为进行增删操作,linkedList较为容易,只需要移动指针
					Integer[] ports = new Integer[]{21, 22, 23, 25, 26, 53,69, 80, 110, 143,
							443,465,69,161,162,135,995,1080,1158,1433,1521,2100, 3128, 3306, 3389,
							7001, 8080, 8081, 9080, 9090, 43958 ,135,445,1025,1026,1027,1028,1055,5357};
					portList.addAll(Arrays.asList(ports));
					//scanPorts为SubmitAction类的内部函数,调用该函数,该函数调用ScanMethod类
					scanPorts(hostname, portList,maxThread, 800);//将主机名,常用端口,线程数与超时时间800ms传参过去
					OwnTCPScan.Submit.setEnabled(true);
					OwnTCPScan.menu0Save.setEnabled(true);
					endTime=System.currentTimeMillis(); //获取结束时间
					System.out.println("n扫描完成n");
					OwnTCPScan.Result.append("n扫描完成n");
					System.out.println("扫描时长为:"+(double)(endTime-startTime)/1000+"s");
					OwnTCPScan.Result.append("扫描时长为:"+(double)(endTime-startTime)/1000+"sn");
				}


				if(OwnTCPScan.radioPart.isSelected()){//指定端口
					//需要继续判断端口输入的有效性
					try{//判断端口号的有效性,整数
						minPort=Integer.parseInt(OwnTCPScan.minPort.getText().trim());
						maxPort=Integer.parseInt(OwnTCPScan.maxPort.getText().trim());

					}
					catch(NumberFormatException e){
						noteDialog("端口号必须存在,并且是整数!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}
					//判断最小端口号的有效范围
					//判断条件:大于0且小于65535,最大端口应大于最小端口
					if(minPort<0 || minPort>65535 || minPort>maxPort){
						noteDialog("最小端口在0-65535之间,且小于最大端口数"+maxPort+"!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}
					else{//最小端口有效,什么也不做
					}
					if(maxPort<0 || maxPort>65535){//判断最大端口号的有效范围;判断条件:大于0且小于65535,最大端口应大于最小端口
						noteDialog("最大端口在0-65535之间,且大于最小端口数"+minPort+"!");
						OwnTCPScan.Submit.setEnabled(true);
						return;
					}
					else{//最大端口号有效,进行端口扫描
						hostname=OwnTCPScan.hostname.getText().trim();
						List portList = new linkedList();// 定义一个List容器表示扫描的团口的List集合
						int length_integer=maxPort-minPort+1;
						Integer[] ports = new Integer[length_integer];
						for (int i=0;i portSet,int threadNumber, int timeout) {//扫描端口,用到ScanMethod类
			ExecutorService threadPool = Executors.newCachedThreadPool();//负责线程的使用和调度的根接口,异步执行机制
			//线程池
			for (int i = 0; i < threadNumber; i++) {
				//10个线程 加入到线程池里
				ScanMethod scanMethod2 = new ScanMethod(ip, portSet,threadNumber, i, timeout);
				//层层传参,传到ScanMethod里面进行端口扫描的实现
				threadPool.execute(scanMethod2);//异步执行
			}
			threadPool.shutdown();
			while (true) {
				if (threadPool.isTerminated()) {
					//如果所有任务都在关闭后完成,则返回true。注意,除非首先调用了shutdown或shutdownNow,否则isTerminated永远不会为真。
					break;
				}
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}// end of while
		}

	}

	//退出功能的提示对话框,使用两次
	private void exitDialog(){
		int n = JOptionPane.show/confirm/iDialog(null, "确认退出吗?", "退出系统", JOptionPane.YES_NO_OPTION);
		if (n == JOptionPane.YES_OPTION) {
			System.exit(0);
		} else if (n == JOptionPane.NO_OPTION) {//关闭对话框,什么都不做

		}
	}

	//扫描端口类,含run方法的实现
	private class ScanMethod implements Runnable {
		private String ip; // 目标IP
		private List portList; // 待扫描的端口的List集合
		private int threadNumber, serial, timeout; // 线程数,这是第几个线程,超时时间
		public ScanMethod(String ip, List portList, int threadNumber,int serial, int timeout) {
			this.ip = ip;//IP地址或主机号
			this.portList = portList;//待扫描端口的LIST集合
			this.threadNumber = threadNumber;
			this.serial = serial;//第几个线程
			this.timeout = timeout;//连接超时时间
		}
		public void run() {
			int port = 0;
			Integer[] ports = portList.toArray(new Integer[portList.size()]); // List转数组
			try {
				InetAddress address = InetAddress.getByName(ip); //InetAddress可以根据主机名获取主机的ip地址,也支持输入IP地址
				Socket socket;//定义套接字,调用connect函数查看端口的状态
				SocketAddress socketAddress;//SocketAddress是一个抽象类,传递ip和端口,其实真正实现的不是SocketAddress,而是其子类,这样声明是为了方便调用
				//必须使用SocketAddress的子类来建立SocketAddress对象
				if (ports.length < 1)
					return;//若数组没有元素,返回,不执行
				for (port = 0 + serial; port <= ports.length - 1; port += threadNumber) {//每次运行maxThread个线程
					socket = new Socket();
					socketAddress = new InetSocketAddress(address, ports[port]);
					//InetSocketAddress是SocketAddress的实现子类,此类实现 IP 套接字地址(IP 地址 + 端口号),不依赖任何协议
					try {
						socket.connect(socketAddress, timeout);
						//对目标主机的指定端口进行连接,超时后连接失败
						socket.close();
						//关闭端口
						System.out.println("端口 " + ports[port] + " :开放");
						OwnTCPScan.Result.append("端口 " + ports[port] + " :开放n");
						//在文本区域里更新消息
					} catch (IOException e) {
						System.out.println("端口 " + ports[port] + " :关闭");
						//OwnTCPScan.Result.append("端口 " + ports[port] + " :关闭n");//产生异常表示端口关闭
					}
				}
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}
		}//end of run()

	}//end of ScanMethod


	//IP地址扫描类,含PingRunner内部类和startPing方法
	class PingTester {
		private Queue allIp;
		private int fetchedNum = 0; // 已经取得的任务数量,每次从队列中取一个ip就加1

		public PingTester(int fromip1,int fromip2,int fromip3,int fromip4,int toip3,int toip4) {
			// 首先创建一个队列用于存储所有ip地址
			allIp = new linkedList();
			int finalip4=0;
			for (int i =fromip3; i <= toip3; i++) {
				if(i 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/531930.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号