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