利用Java实现端口扫描器
生活随笔
收集整理的這篇文章主要介紹了
利用Java实现端口扫描器
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
上次我們用Java寫了一個(gè)“文件最后修改時(shí)間編輯器”的小黑軟,現(xiàn)在我們實(shí)現(xiàn)用Java寫端口掃描器。為了方便和避免GUI編程的麻煩,我們就直接做成命令行下的工具,用參數(shù)來(lái)啟動(dòng)它,姑且把它命名為“Java版簡(jiǎn)單端口掃描工具”。因?yàn)楸疚闹皇翘峁㎎ava寫黑軟的思路,許多算法優(yōu)化和功能附加不在本文的討論之列,使用的也是單線程。程序界面如圖1所示。
圖1
我們知道,利用java.net.Socket類建立socket連接,如果無(wú)法與指定的IP和端口建立連接,將會(huì)拋出IOException。我們用try-catch對(duì)這個(gè)IOException異常進(jìn)行捕獲,以判斷是否成功與指定的IP端口建立連接。如果成功建立了連接,說(shuō)明指定IP的指定端口已經(jīng)開(kāi)放;如果程序拋出了一個(gè)IOException異常被我們捕獲,則說(shuō)明指定的IP沒(méi)有開(kāi)放指定的端口。掃描指定端口段則是利用循環(huán)不斷與服務(wù)器的指定端口進(jìn)行連接,供我們判斷是否開(kāi)放。
我一直堅(jiān)信,世界上的所有問(wèn)題只要有了明確的算法,就一定能用程序語(yǔ)言來(lái)實(shí)現(xiàn)它,無(wú)論什么語(yǔ)言!現(xiàn)在,我們有了原理就等于有了算法,你說(shuō)我們除了技術(shù)以外還缺什么?只缺動(dòng)手了!
因?yàn)槲覀円獜某绦騿?dòng)的參數(shù)中獲得服務(wù)器地址、起始端口和終止端口的信息,所以我們就要用到下面的這段代碼。
ip = args[0]; //獲得我們指定的服務(wù)器地址
startPort = Integer.parseInt(args[1]);
//獲得起始端口號(hào),因?yàn)閍rgs[]是String類型,所以要強(qiáng)制轉(zhuǎn)換成int類型
endPort = Integer.parseInt(args[2]);
//獲得終止端口號(hào),同上
在得到端口和建立socket之前一定要判斷端口的合法性,因?yàn)槎丝诘姆秶窃?~65535,如果我們?nèi)ソ⒎秶舛丝诘倪B接就是沒(méi)必要的,而且是不可行的。既然是起始端口和終止端口,那么就要有個(gè)大小順序問(wèn)題,也就是判斷它們的大小。
if(startPort<1||startPort>65535||endPort<1||endPort>65535){
//檢查端口是否在合法范圍1~65535
System.out.printf("端口范圍必須在1~65535以內(nèi)!");
return;
}else if(startPort>endPort){ //比較起始端口和終止端口
System.out.println("端口輸入有誤! 起始端口必須小于終止端口");
return;
}? ? ? ? ? ? ? ?
建立與服務(wù)器指定端口的連接,就要用到j(luò)ava.net.Socket類了,首先我們來(lái)看看它的構(gòu)造方法。
Socket():通過(guò)系統(tǒng)默認(rèn)類型的 SocketImpl 創(chuàng)建未連接套接字。
Socket(InetAddress address, int port):創(chuàng)建一個(gè)流套接字,并將其連接到指定 IP 地址的指定端口號(hào)。
Socket(InetAddress address, int port, InetAddress localAddr, int localPort):創(chuàng)建一個(gè)套接字,并將其連接到指定遠(yuǎn)程端口上的指定遠(yuǎn)程地址。
Socket(Proxy proxy):根據(jù)不管其他設(shè)置如何都應(yīng)使用的指定代理類型(如果有),創(chuàng)建一個(gè)未連接的套接字。
Socket(SocketImpl impl):創(chuàng)建帶有用戶指定的 SocketImpl 的未連接Socket。
Socket(String host, int port):創(chuàng)建一個(gè)流套接字,并將其連接到指定主機(jī)上的指定端口號(hào)。
Socket(String host, int port, InetAddress localAddr, int localPort):創(chuàng)建一個(gè)套接字并將其連接到指定遠(yuǎn)程主機(jī)上的指定遠(yuǎn)程端口。
可以看到我們有很多種構(gòu)造方法,目前只需要關(guān)心第二種構(gòu)造方法Socket(InetAddress address, int port)即可,因?yàn)槲覀儾⒉恍枰c服務(wù)器運(yùn)行在端口的服務(wù)進(jìn)行交互,所以我們只要建立連接,然后關(guān)閉連接即可。即:“Socket s = new Socket(address,port);”。
我們?cè)诮⑦B接之前,首先要把IP轉(zhuǎn)換成InetAddress類型,不是說(shuō)String類型不能用,只是為了減少出現(xiàn)更多異常的可能。
“static InetAddress getByName(String host)”用于在給定主機(jī)名的情況下確定主機(jī)的 IP 地址。這是靜態(tài)方法,我們直接InetAddress.getByName()就行了。
try{
InetAddress address = InetAddress.getByName(ip);
//轉(zhuǎn)換類型
}catch(UnknownHostException e){
System.out.println("無(wú)法找到 "+ ip);
return;
}
下面就是我們的核心算法了。循環(huán)指定端口段的所有端口,對(duì)所有端口建立連接。連接成功后我們就算完成了當(dāng)前循環(huán)的任務(wù),然后調(diào)用close()方法關(guān)閉連接。因?yàn)樵凇癝ocket s = new Socket(address,nport)”執(zhí)行的時(shí)候,如果成功建立連接,就不會(huì)執(zhí)行到catch里面,而是執(zhí)行到下面的“result.add(“”+nport)”語(yǔ)句;如果不能連接上去就會(huì)拋出一個(gè)異常被我們捕獲,程序就會(huì)運(yùn)行到catch里面,執(zhí)行catch里面的語(yǔ)句;最后繼續(xù)下一個(gè)循環(huán)。
for(int nport=startPort;nport<=endPort;nport++){? ? ? ? ? ? ? ?
//從起始端口到終止端口進(jìn)行循環(huán)
try{
System.out.print("Scanning "+nport);? ? ? ? ? ? ? ? //打印掃描進(jìn)度
Socket s=new Socket(address,nport);? ? ? ? ? ? ? ? //建立連接
s.close();? ? ? ? ? ? ? ? //關(guān)閉連接
result.add(""+nport);
//將打開(kāi)的端口添加到ArrayList result里面
System.out.println(" : open"); //打印狀態(tài)
}catch(IOException e){
System.out.println(":close"); //打印狀態(tài)
}
}
在最后打印結(jié)果時(shí),我們用ArrayList來(lái)存儲(chǔ)掃描結(jié)果。因?yàn)镴ava里面沒(méi)有C語(yǔ)言意義上的指針,所以我們?cè)谠L問(wèn)ArrayList里面的元素時(shí)要用到ListIterator。
ListIterator li = result.listIterator();
//獲得ArrayList的ListIterator
while(li.hasNext()){ //如果li里面有元素
System.out.println(li.next().toString()+" Open");? ? ? ? ? ? ? ?
//打印出指向的元素,同時(shí)將指向下一個(gè)元素
}
好了,現(xiàn)在我們就已經(jīng)把主要功能的程序代碼介紹完了,相信讀者看完以后也能用Java編寫自己的Java版黑軟了。正如我前面所說(shuō)的,本文只提供一種思路。如果大家有興趣,可以自己在本文的基礎(chǔ)上實(shí)現(xiàn)多線程,擴(kuò)展一些有用的功能,把GUI界面做出來(lái),或者做成仿SuperScan就更強(qiáng)大了
圖1
我們知道,利用java.net.Socket類建立socket連接,如果無(wú)法與指定的IP和端口建立連接,將會(huì)拋出IOException。我們用try-catch對(duì)這個(gè)IOException異常進(jìn)行捕獲,以判斷是否成功與指定的IP端口建立連接。如果成功建立了連接,說(shuō)明指定IP的指定端口已經(jīng)開(kāi)放;如果程序拋出了一個(gè)IOException異常被我們捕獲,則說(shuō)明指定的IP沒(méi)有開(kāi)放指定的端口。掃描指定端口段則是利用循環(huán)不斷與服務(wù)器的指定端口進(jìn)行連接,供我們判斷是否開(kāi)放。
我一直堅(jiān)信,世界上的所有問(wèn)題只要有了明確的算法,就一定能用程序語(yǔ)言來(lái)實(shí)現(xiàn)它,無(wú)論什么語(yǔ)言!現(xiàn)在,我們有了原理就等于有了算法,你說(shuō)我們除了技術(shù)以外還缺什么?只缺動(dòng)手了!
因?yàn)槲覀円獜某绦騿?dòng)的參數(shù)中獲得服務(wù)器地址、起始端口和終止端口的信息,所以我們就要用到下面的這段代碼。
ip = args[0]; //獲得我們指定的服務(wù)器地址
startPort = Integer.parseInt(args[1]);
//獲得起始端口號(hào),因?yàn)閍rgs[]是String類型,所以要強(qiáng)制轉(zhuǎn)換成int類型
endPort = Integer.parseInt(args[2]);
//獲得終止端口號(hào),同上
在得到端口和建立socket之前一定要判斷端口的合法性,因?yàn)槎丝诘姆秶窃?~65535,如果我們?nèi)ソ⒎秶舛丝诘倪B接就是沒(méi)必要的,而且是不可行的。既然是起始端口和終止端口,那么就要有個(gè)大小順序問(wèn)題,也就是判斷它們的大小。
if(startPort<1||startPort>65535||endPort<1||endPort>65535){
//檢查端口是否在合法范圍1~65535
System.out.printf("端口范圍必須在1~65535以內(nèi)!");
return;
}else if(startPort>endPort){ //比較起始端口和終止端口
System.out.println("端口輸入有誤! 起始端口必須小于終止端口");
return;
}? ? ? ? ? ? ? ?
建立與服務(wù)器指定端口的連接,就要用到j(luò)ava.net.Socket類了,首先我們來(lái)看看它的構(gòu)造方法。
Socket():通過(guò)系統(tǒng)默認(rèn)類型的 SocketImpl 創(chuàng)建未連接套接字。
Socket(InetAddress address, int port):創(chuàng)建一個(gè)流套接字,并將其連接到指定 IP 地址的指定端口號(hào)。
Socket(InetAddress address, int port, InetAddress localAddr, int localPort):創(chuàng)建一個(gè)套接字,并將其連接到指定遠(yuǎn)程端口上的指定遠(yuǎn)程地址。
Socket(Proxy proxy):根據(jù)不管其他設(shè)置如何都應(yīng)使用的指定代理類型(如果有),創(chuàng)建一個(gè)未連接的套接字。
Socket(SocketImpl impl):創(chuàng)建帶有用戶指定的 SocketImpl 的未連接Socket。
Socket(String host, int port):創(chuàng)建一個(gè)流套接字,并將其連接到指定主機(jī)上的指定端口號(hào)。
Socket(String host, int port, InetAddress localAddr, int localPort):創(chuàng)建一個(gè)套接字并將其連接到指定遠(yuǎn)程主機(jī)上的指定遠(yuǎn)程端口。
可以看到我們有很多種構(gòu)造方法,目前只需要關(guān)心第二種構(gòu)造方法Socket(InetAddress address, int port)即可,因?yàn)槲覀儾⒉恍枰c服務(wù)器運(yùn)行在端口的服務(wù)進(jìn)行交互,所以我們只要建立連接,然后關(guān)閉連接即可。即:“Socket s = new Socket(address,port);”。
我們?cè)诮⑦B接之前,首先要把IP轉(zhuǎn)換成InetAddress類型,不是說(shuō)String類型不能用,只是為了減少出現(xiàn)更多異常的可能。
“static InetAddress getByName(String host)”用于在給定主機(jī)名的情況下確定主機(jī)的 IP 地址。這是靜態(tài)方法,我們直接InetAddress.getByName()就行了。
try{
InetAddress address = InetAddress.getByName(ip);
//轉(zhuǎn)換類型
}catch(UnknownHostException e){
System.out.println("無(wú)法找到 "+ ip);
return;
}
下面就是我們的核心算法了。循環(huán)指定端口段的所有端口,對(duì)所有端口建立連接。連接成功后我們就算完成了當(dāng)前循環(huán)的任務(wù),然后調(diào)用close()方法關(guān)閉連接。因?yàn)樵凇癝ocket s = new Socket(address,nport)”執(zhí)行的時(shí)候,如果成功建立連接,就不會(huì)執(zhí)行到catch里面,而是執(zhí)行到下面的“result.add(“”+nport)”語(yǔ)句;如果不能連接上去就會(huì)拋出一個(gè)異常被我們捕獲,程序就會(huì)運(yùn)行到catch里面,執(zhí)行catch里面的語(yǔ)句;最后繼續(xù)下一個(gè)循環(huán)。
for(int nport=startPort;nport<=endPort;nport++){? ? ? ? ? ? ? ?
//從起始端口到終止端口進(jìn)行循環(huán)
try{
System.out.print("Scanning "+nport);? ? ? ? ? ? ? ? //打印掃描進(jìn)度
Socket s=new Socket(address,nport);? ? ? ? ? ? ? ? //建立連接
s.close();? ? ? ? ? ? ? ? //關(guān)閉連接
result.add(""+nport);
//將打開(kāi)的端口添加到ArrayList result里面
System.out.println(" : open"); //打印狀態(tài)
}catch(IOException e){
System.out.println(":close"); //打印狀態(tài)
}
}
在最后打印結(jié)果時(shí),我們用ArrayList來(lái)存儲(chǔ)掃描結(jié)果。因?yàn)镴ava里面沒(méi)有C語(yǔ)言意義上的指針,所以我們?cè)谠L問(wèn)ArrayList里面的元素時(shí)要用到ListIterator。
ListIterator li = result.listIterator();
//獲得ArrayList的ListIterator
while(li.hasNext()){ //如果li里面有元素
System.out.println(li.next().toString()+" Open");? ? ? ? ? ? ? ?
//打印出指向的元素,同時(shí)將指向下一個(gè)元素
}
好了,現(xiàn)在我們就已經(jīng)把主要功能的程序代碼介紹完了,相信讀者看完以后也能用Java編寫自己的Java版黑軟了。正如我前面所說(shuō)的,本文只提供一種思路。如果大家有興趣,可以自己在本文的基礎(chǔ)上實(shí)現(xiàn)多線程,擴(kuò)展一些有用的功能,把GUI界面做出來(lái),或者做成仿SuperScan就更強(qiáng)大了
總結(jié)
以上是生活随笔為你收集整理的利用Java实现端口扫描器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【2023计算机考研】985院校录取分数
- 下一篇: Java面向对象程序设计 期末复习