我用C++编写了一个端口扫描仪,它将在使用winsock的窗口中工作,一切都按照我想要的方式工作。只是它非常非常慢,扫描三个端口大约需要10分钟。我只是想知道是否有办法提高它的性能!
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <winsock.h>
#include <stdlib.h>
#pragma comment(lib,"WSOCK32.LIB")
int main()
{
WSADATA data;
SOCKET sock;
int err, i, startport, endport;
char ip[20];
struct sockaddr_in sock_addr;
FILE*fp1;
printf("ip: ");
scanf("n%s", ip);
printf("start port: ");
scanf("%d", &startport);
printf("end port: ");
scanf("%d", &endport);
if ((WSAStartup(MAKEWORD(2, 0), &data) != 0))
{
printf("Error: Winsock did not init!!!nn");
}
else
{
for (i = startport; i < endport; i++)
{
sock = socket(AF_INET, SOCK_STREAM, 0);
sock_addr.sin_family = PF_INET;
sock_addr.sin_port = htons(i);
sock_addr.sin_addr.s_addr = inet_addr(ip);
printf("Checking port %dn", i);
err = connect(sock, (struct sockaddr*)&sock_addr, sizeof(struct sockaddr));
if (err == 0)
{
printf("Port Open!!!nna");
fp1 = fopen("ports.txt", "a+");
fprintf(fp1, "Port is open: %dnn", i);
closesocket(sock);
fclose(fp1);
}
else
{
printf("Port Closed!!!nn");
}
}
WSACleanup();
system("ports.txt");
}
}
默认情况下,套接字在阻塞模式下运行。您使用单个循环以串行方式连接到每个端口,等待一个连接完成后再尝试下一个连接。所以,性能当然会很慢。
为了实现您想要实现的目标,您需要并行运行多个连接调用。你有三个选择:
- 使用线程
对于您创建的每个阻塞套接字,启动一个工作线程来connect()
它。然后您可以创建多个套接字并一次运行它们的线程。使用WaitForMultipleObjects()
(或相关函数(检测每个线程在其connect()
操作完成时何时终止。
这对于少量的套接字来说是可以的,但对于大量的套接字来说则不适用。
- 使用非阻塞套接字
对于您创建的每个套接字,使用ioctlsocket(FIONBIO)
将其置于非阻塞模式。然后,您可以创建多个套接字并一次connect()
它们。使用select()
、WSAAsyncSelect()
或WSAEventSelect()
来检测每个connect()
操作何时完成。
- 使用重叠套接字I/O
使用启用WSA_FLAG_OVERLAPPED
标志的WSASocket()
创建每个套接字。然后,您可以创建多个套接字并一次创建ConnectEx()
,为每个套接字指定一个单独的OVERLAPPED
结构。使用WaitForMultipleObjects()
+GetOverlappedResult()
或I/O完成端口来检测每个ConnectEx()
操作何时完成。