2013-05-06 164 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); 
} 

,似乎现在快得多的功能!我会做一些工作来优化它&清理它一下,但是感谢所有你输入的每个人的回应! :)