链接::l基于JAVA的系统端口扫描软件设计实现(java代码+IDEA+UI图形界面+实验报告)
系统端口扫描软件设计实现
设计目的和任务
参照superscan、nmap等端口扫描软件的运行情况,自行设计一个简单的端口扫描软件,能够根据TCP、IMCP等探测方法,探测目标主机开放的端口。
要求:
(1)用ping扫描测试目标主机的连通状态,若ping不通,则显示主机不在网络。
(2) 若ping可达,则设计程序对目标主机进行端口扫描,显示常见端口的扫描结果,识别目标操作系统类型。
(3)使用多线程实现能同时扫描多台主机。设计程序对IP地址(单个IP,一段IP范围)、指定主机名的端口(指定端口,所有端口)进行扫描,以获得相关的信息。
(4)友好地图形用户界面,扫描过程中能显示扫描进度,扫描时间,异常告警窗口(如IP地址范围出界等),在局域网段实现。
三、实验环境和总体设计
实验环境:Window XP系统、java虚拟机、JDK1.8.1和IDEA..1
总体设计:端口扫描系统分为两个界面,分别是用户登陆界面和功能界面。在用户登录界面中,设置了一个登陆的账号密码管理校检机制,使软件的使用更加严密、可靠;功能界面是由菜单栏,IP扫描,端口扫描和扫描结果等控件组成的一个完整简介,功能齐全的操作界面,充分的从用户感受出发,最大化满足用户的需求。
五、结果测试与分析
登陆界面:
首先打开的是账户登陆界面,它由账号输入文本框,密码输入文本框,界面标题,最小化按钮,登录按钮和关闭按钮组成,背景颜色为灰白色,文本大小适中,字体为微软雅黑,居中。需要用户在文本框内输入正确的帐号和密码,再点击“登陆”按钮,与后台预设的账号密码进行比对,校检正确之后才能进入下操作界面。如果账号输入错误,会弹出错误警告窗口;如果密码输入错误,会弹出警告窗口。只有账号和密码输入正确,才能进入操作界面。
账号输入错误: 正确账号是“admin”
密码输入错误: 正确密码是“123456”
验证成功:
操作界面:
通过了安全性验证之后,就可以开始端口扫描操作。操作界面由标题,菜单栏,扫描方式选择(IP扫描,端口扫描),ip地址段输入框,端口号输入框,线程数输入框,开始扫描按钮,退出按钮,清空按钮,扫描结果显示区。根据用户的需求选择扫描的方式:对ip地址扫描或者扫描目的主机的端口号。如果选择的是ip地址扫描,还可以继续选择对单个ip地址进行扫描,或者对一段ip地址进行扫描,此外还会对输入的ip地址进行合法性检验,否则会显示ip输入错误警告;如果选择的是对端口扫描,首先需要输入目的主机的ip地址,通过ip地址合法性检验之后,再选择对常用端口扫描或者是指定端口扫描。软件支持多线程扫描,可以自定义最大线程数,利用多线程来提高端口扫描的时间效率。扫描结果会在操作页面的下半部分显示出扫描时间,ip地址是否可达,端口开放状态,目的主机操作系统类型。
扫描IP地址可能出现的异常:通过try-catch捕获异常
Ip地址输入合法性:
Ip地址输入越界性:
Ip地址输入逻辑性:
扫描目的主机端口号可能出现的异常:通过try-catch捕获异常
目的主机ip地址输入错误:
端口号输入越界性:
端口号输入逻辑性:
多线程:通过java.util.concurrent.ExecutorService包生成一个固定数量的线程池,执行多线程服务:
ExecutorService executor = Executors.newFixedThreadPool(threadNum)
再通过executor.execute(new PingRunner())与threadPool.execute(scanMethod)开启多线程ping扫描和端口号扫描。
线程数输入合法性:
四、详细设计步骤
账户登陆模块:在用户登陆界面中,需要输入“账号”和“密码”,密码正确才能跳转到操作页面,否则不能进行扫描操作。
关键算法:
//用户名正确,比较密码,equals():比较字符串是否相等
if (username.getText().trim().equals("admin")) {// getText():得到输入的密码
boolean isCorrect = true;// trim()去掉字符串的首尾空格
char[] ch1 = pwd.getPassword();//ch1是用户输入的密码
char[] ch2 = s.toCharArray();//ch2是默认密码
if (ch1.length == ch2.length) { //如果长度相等,再比较
for (int i = 0; i < ch1.length; i++) {
if (clearText.indexOf(ch1[i])!= cipherText.indexOf(ch2[i])) {
isCorrect = false; //只要有不等的,就为错
break;
} else {//长度不等,直接错误
isCorrect = false;}}
}
流程图:
IP扫描模块:IP地址扫描分为单地址和多地址两种,以用户输入的IP地址和线程数为参数采用多线程的方式扫描IP地址;调用PingTester类实现IP地址扫描,PingTester类包含3个部分:构造函数、startPing函数、内部类PingRunner。
关键算法:
try { //InetAddress保存了主机名和IP地址
while ((taskIp = getIp()) != null) { //调用getIp()方法得到IP地址
InetAddress addr = InetAddress.getByName(taskIp);//获得IP地址
//isReachable()测试该地址是否可到达。实现会尽最大努力尝试访问主机,
if (addr.isReachable(5000)) { //访问超时时间为5s
System.out.println("IP地址 ["+taskIp+"]是可达的");
OwnTCPScan.Result.append("IP地址 ["+taskIp+"]是可达的"+"\n");
} else { //System.out.println("")在后端显示扫描结果
System.out.println("IP地址 ["+taskIp+"]不在网络");
OwnTCPScan.Result.append("IP地址 ["+taskIp+"]不在网络"+"\n");
} //OwnTCPScan.Result.append("")在UI界面显示扫描结果
}
} catch (SocketException e) { //如果访问超时
System.out.println("IP地址 ["+taskIp+"]没有访问权限");
OwnTCPScan.Result.append("IP地址 ["+taskIp+"]没有访问权限"+"\n");}
流程图:
端口扫描模块:根据主机和端口号的扫描采用多线程技术,以用户输入的主机名、线程数与端口范围为参数进行多线程扫描,调用scanPorts函数传递参数,scanPorts函数调用ScanMethod类实现端口的扫描。主要分为3个部分:scanPorts函数、ScanMethod类的构造函数、ScanMethod类的run函数。
关键代码:
try {//包中有InetAddress类的定义,用于IP地址和域名
InetAddress address = InetAddress.getByName(ip);
//InetAddress可以根据主机名获取主机的ip地址,也支持输入IP地址
Socket socket;//定义套接字,调用connect函数查看端口的状态
SocketAddress socketAddress;//SocketAddress是一个抽象类,传递ip和端口,其实真正实现的不是SocketAddress,而是其子类,这样声明是为了方便调用
//必须使用SocketAddress的子类来建立SocketAddress对象
if (ports.length < 1) {
return;//若数组没有元素,返回,不执行
}
//serial是线程号,1号线程检测1,11,21端口,2号线程检测2,12,22端口
for (port = 0 + serial; port <= ports.length - 1; port += threadNumber) {
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();
}
}
流程图::