所以今天早上我用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 :(得分:2)
当您呼叫connect(2)
时,操作系统会通过向另一个对等方发送SYN
数据包来启动three-way handshake。如果没有收到响应,它会稍微等待并发送一些SYN
个数据包。如果在给定超时后仍未收到任何响应,则操作将失败,connect(2)
将返回错误代码ETIMEODOUT
。
通常,如果对等体已启动但未接受给定端口上的TCP连接,则它将回复具有SYN
数据包的任何RST
数据包。这将导致connect(2)
失败得更快(一个网络往返时间),错误为ECONNREFUSED
。但是,如果对等方设置了防火墙,它将忽略您的SYN
数据包,并且不会发送那些RST
数据包,这将导致connect(2)
花费很长时间失败。
因此,如果您想避免等待每个端口的超时,则需要并行执行多个连接。您可以执行此多线程(每个线程一次同步connect(2)
调用),但由于线程占用了大量资源,因此无法很好地扩展。
更好的方法是使用非阻塞套接字。要使套接字无阻塞,请使用F_SETFL
选项和O_NONBLOCK
选项调用fcntl(2)
。然后,connect(2)
将立即返回EWOULDBLOCK
或EAGAIN
,此时您可以使用select(2)
或poll(2)
和朋友来监控大量的一次插座。
答案 1 :(得分:1)
尝试创建一个非阻塞套接字数组,以便一次排队一堆连接尝试。
了解here
答案 2 :(得分: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);
}
现在看起来功能要快得多!我会做一些工作来优化它&amp;清理一下,但感谢所有回复的人! :)