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;
}