1、使用 socket 编程
利用原始套接字直接发送TCP或UDP数据包来探测目标主机的端口状态。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> void scan_port(const char *ip, int port) { int sock; struct sockaddr_in server; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { return; // socket 创建失败 } server.sin_family = AF_INET; server.sin_port = htons(port); inet_pton(AF_INET, ip, &server.sin_addr); if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) { printf("端口 %d 开放\n", port); } close(sock); } int main() { const char *ip = "127.0.0.1"; // 可以修改为目标 IP printf(ip); for (int port = 1; port <= 1024; port++) { scan_port(ip, port); } return 0; }
2、使用多线程
通过 pthread
实现多线程扫描,以提高扫描速度。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <pthread.h> #define MAX_PORT 1024 typedef struct { const char *ip; int port; } port_scan_arg; void *scan_port(void *arg) { port_scan_arg *p = (port_scan_arg *)arg; int sock; struct sockaddr_in server; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) return NULL; server.sin_family = AF_INET; server.sin_port = htons(p->port); inet_pton(AF_INET, p->ip, &server.sin_addr); if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) { printf("端口 %d 开放\n", p->port); } close(sock); return NULL; } int main() { const char *ip = "127.0.0.1"; // 可以修改为目标 IP pthread_t threads[MAX_PORT]; for (int port = 1; port <= MAX_PORT; port++) { port_scan_arg *arg = malloc(sizeof(port_scan_arg)); arg->ip = ip; arg->port = port; pthread_create(&threads[port], NULL, scan_port, arg); } for (int port = 1; port <= MAX_PORT; port++) { pthread_join(threads[port], NULL); } return 0; }
3、使用非阻塞套接字进行端口扫描
通过设置套接字为非阻塞模式,并使用select
函数来检测端口状态,从而提高扫描效率。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <fcntl.h> #include <errno.h> #include <sys/select.h> void scan_port(const char *ip, int port) { int sock; struct sockaddr_in server; fd_set fdset; struct timeval tv; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return; } // 设置为非阻塞 fcntl(sock, F_SETFL, O_NONBLOCK); server.sin_family = AF_INET; server.sin_port = htons(port); inet_pton(AF_INET, ip, &server.sin_addr); // 尝试连接 if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) { if (errno != EINPROGRESS) { close(sock); return; // 连接失败 } } // 使用 select 等待连接完成 FD_ZERO(&fdset); FD_SET(sock, &fdset); tv.tv_sec = 1; // 超时时间 1 秒 tv.tv_usec = 0; if (select(sock + 1, NULL, &fdset, NULL, &tv) > 0) { // 检查连接是否成功 int so_error; socklen_t len = sizeof(so_error); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len) < 0) { close(sock); return; // 获取错误信息失败 } if (so_error == 0) { printf("端口 %d 开放\n", port); // 连接成功 } } close(sock); // 关闭套接字 } int main() { const char *ip = "127.0.0.1"; // 可以修改为目标 IP printf(ip); for (int port = 1; port <= 1024; port++) { scan_port(ip, port); } return 0; }