2013-05-06 160 views
1

所以我今天早上在C++上製作了一個端口掃描器,它似乎能夠正常工作,只是有一個令人討厭的問題 - 每當我用它在網絡上掃描IP時,它都需要10每個端口-20秒。提高端口掃描器的性能

好像connect()方法是這麼長時間。

現在除了多線程之外,我敢肯定會加快這個過程但不會太多,我怎麼能讓這個更快?這裏是掃描的代碼段:

for (i = 0; i < a_size(port_no); i++) 
{ 
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

    target.sin_family = AF_INET; 
    target.sin_port = htons(port_no[i]); 
    target.sin_addr.s_addr = inet_addr(argv[1]); 

    if (connect(sock, (SOCKADDR *)&target, sizeof(target)) != SOCKET_ERROR) 
     cout << "Port: " << port_no[i] << " - open" << endl; 
    else 
     cout << "Port: " << port_no[i] << " - closed" << endl; 
    closesocket(sock); 
} 

如果你需要更多的讓我知道。

另外,我正在使用winsock2.h文件。是不是因爲這麼慢?

+0

可能會有某種超時丟失。 – Drise 2013-05-06 22:11:11

+2

如果你想減少等待連接的時間,使它成爲一個非阻塞套接字並在'connect'後調用'select'。 – 2013-05-06 22:11:54

+0

@CaptainObvlious,我其實也覺得我在某處在線閱讀。今天晚些時候,當我有機會的時候,我會再試一次。謝謝! – user1324674 2013-05-06 22:12:59

回答

1

嘗試創建一個非阻塞套接字的數組,以一次排隊一堆連接嘗試。

讀到它here

+0

糟糕,似乎我太遲了,因爲這已經在評論中提出。 – rickythefox 2013-05-06 22:13:53

2

當你調用connect(2),操作系統通過發送SYN包到其他同行發起three-way handshake。如果沒有收到響應,它會稍微等待併發送一些更多SYN數據包。如果在給定超時後沒有收到響應,則操作失敗,並且connect(2)返回,錯誤代碼爲ETIMEODOUT

通常情況下,如果一個對等設備啓動但不接受給定端口上的TCP連接,它將回復任何帶有RST數據包的SYN數據包。這將導致connect(2)以更快的速度(一個網絡往返時間)發生故障,並顯示錯誤ECONNREFUSED。但是,如果對等端設置了防火牆,它將忽略您的SYN數據包,並且不會發送這些數據包,這將導致connect(2)花費很長時間纔會失敗。

因此,如果您希望避免等待每個端口的超時,您需要並行執行多個連接。您可以執行此多線程(每個線程調用一個同步connect(2)),但由於線程佔用大量資源,因此不能很好地擴展。

更好的方法是使用非阻塞套接字。要使插座無阻塞,請撥打fcntl(2),並輸入F_SETFL選項和O_NONBLOCK選項。然後,connect(2)將立即返回EWOULDBLOCKEAGAIN,此時您可以使用select(2)poll(2)和朋友一次監視大量套接字。

+0

當我將F_SETFL和O_NONBLOCK傳遞給fcntl()時,我的編譯器拋出一個錯誤,表示它們沒有被聲明。我似乎找不到任何需要任何人聲明它們的文檔或示例... 我在網上找到的所有示例都是按照原樣傳遞它們的。 fcntl本身沒有任何編譯問題 – user1324674 2013-05-08 19:05:53

+0

@ user1324674:確保你包含'#include '。另外,爲了確保您不會取消之前設置的任何標誌,您還需要執行'F_GETFL'。所以要設置'O_NONBLOCK',你需要'fcntl(fd,F_SETFL,fcntl(fd,F_GETFL)| O_NONBLOCK);'(但是不要忘記添加錯誤檢查)。 – 2013-05-10 15:55:07

+0

我想我沒有提到我在這個項目中使用Windows。 顯然fcntl在這裏不起作用 – user1324674 2013-05-13 16:57:16

0

我想出了一個適用於Windows的解決方案。首先我說:

u_long on = 1; 
timeval tv = {0, 1000};  //timeout value in microseconds 
fd_set fds; 
FD_ZERO(&fds); 

然後我改變了這種代碼看起來像這樣:

for (i = 0; i < a_size(port_no); i++) 
{ 
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    FD_SET(sock, &fds); 

    ioctlsocket(sock, FIONBIO, &on); 

    target.sin_family = AF_INET; 
    target.sin_port = htons(port_no[i]); 
    target.sin_addr.s_addr = inet_addr(argv[1]); 

    connect(sock, (SOCKADDR *)&target, sizeof(target)); 
    err = select(sock, &fds, &fds, &fds, &tv); 

    if (err != SOCKET_ERROR && err != 0) 
     cout << "Port: " << port_no[i] << " - open" << endl; 
    else 
     cout << "Port: " << port_no[i] << " - closed" << endl; 
    closesocket(sock); 
} 

,似乎現在快得多的功能!我會做一些工作來優化它&清理它一下,但是感謝所有你輸入的每個人的迴應! :)