如何为C语言Socket服务器添加本地连接IP的端口扫描功能?
为你的C语言Socket服务器添加端口扫描功能
没问题,我帮你把端口扫描功能整合到现有的Socket服务器里。咱们先修正原代码里的一些小问题(比如不安全的gets函数),再补上完整的端口扫描逻辑,还能让你直接选择已连接的客户端IP来扫描,不用重复输入。
核心修改说明
- 替换不安全的输入函数:把
gets(hostname)换成更安全的输入方式,避免缓冲区溢出风险 - 添加端口扫描核心函数:写一个
scan_ports函数,负责遍历指定端口范围,尝试连接目标IP的端口并判断是否开放 - 优化交互流程:让你可以直接选择已显示的客户端IP进行扫描,不用手动输入,更贴合你的需求
修改后的完整代码
#include <netdb.h> #include <netinet/in.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/time.h> #define MAX 80 #define PORT 8080 #define SA struct sockaddr // 端口扫描函数:扫描目标IP的start到end端口 void scan_ports(const char* target_ip, int start_port, int end_port) { printf("\n开始扫描IP: %s,端口范围: %d-%d\n", target_ip, start_port, end_port); for (int port = start_port; port <= end_port; port++) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("创建扫描socket失败"); continue; } // 设置连接超时(避免长时间阻塞在未开放的端口) struct timeval timeout; timeout.tv_sec = 1; // 1秒超时 timeout.tv_usec = 0; setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); struct sockaddr_in target_addr; memset(&target_addr, 0, sizeof(target_addr)); target_addr.sin_family = AF_INET; target_addr.sin_port = htons(port); inet_pton(AF_INET, target_ip, &target_addr.sin_addr); // 尝试连接端口:连接成功则说明端口开放 int result = connect(sock, (SA*)&target_addr, sizeof(target_addr)); if (result == 0) { printf("端口 %d 开放\n", port); } close(sock); } printf("扫描完成\n"); } // Driver function int main() { int sockfd, connfd, len, start, end, choice; struct sockaddr_in servaddr, addr_remote; char ips[2][20]; // socket create and verification sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { printf("socket creation failed...\n"); exit(EXIT_FAILURE); } else { printf("Socket successfully created..\n"); } bzero(&servaddr, sizeof(servaddr)); // assign IP, PORT servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(PORT); // Binding newly created socket to given IP and verification if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) { printf("socket bind failed...\n"); exit(EXIT_FAILURE); } else { printf("Socket successfully binded..\n"); } // Now server is ready to listen and verification if ((listen(sockfd, 5)) != 0) { printf("Listen failed...\n"); exit(EXIT_FAILURE); } else { printf("Server listening..\n"); } len = sizeof(addr_remote); // Accept up to 2 clients and store their IPs for (int i = 0; i < 2; i++) { connfd = accept(sockfd, (SA*)&addr_remote, &len); if (connfd < 0) { printf("server accept failed...\n"); exit(EXIT_FAILURE); } else { printf("server accepted client %d...\n", i+1); strcpy(ips[i], inet_ntoa(addr_remote.sin_addr)); close(connfd); // 仅获取IP,不需要保持连接 } } // Display connected client IPs printf("\n已连接的客户端IP列表:\n"); for (int i = 0; i < 2; i++) { printf("%d. %s\n", i+1, ips[i]); } // 选择要扫描的IP printf("\n请选择要扫描的IP序号(1或2): "); scanf("%d", &choice); while (choice < 1 || choice > 2) { printf("无效序号,请重新输入(1或2): "); scanf("%d", &choice); } const char* target_ip = ips[choice-1]; // Get start port number(带输入校验) printf("Enter start port number: "); while (scanf("%d", &start) != 1 || start < 1 || start > 65535) { printf("无效端口,请输入1-65535之间的数字: "); // 清除输入缓冲区的垃圾数据 while (getchar() != '\n'); } // Get end port number(带输入校验) printf("Enter end port number: "); while (scanf("%d", &end) != 1 || end < start || end > 65535) { printf("无效端口,请输入大于等于起始端口且<=65535的数字: "); while (getchar() != '\n'); } // 执行端口扫描 scan_ports(target_ip, start, end); // Close server socket close(sockfd); return 0; }
关键功能说明
端口扫描逻辑:
- 对每个端口创建独立的TCP socket,避免单个socket异常影响整个扫描流程
- 设置1秒连接超时,防止程序在未开放的端口上长时间阻塞
- 通过
connect函数的返回值判断端口状态:连接成功则端口开放
输入校验优化:
- 对端口输入做了范围校验(1-65535是TCP端口的合法范围)
- 选择IP时做了序号校验,避免输入错误导致程序崩溃
资源管理:
- 接受客户端连接后立即关闭
connfd,因为我们只需要获取客户端IP - 每个扫描用的socket用完后及时关闭,避免系统资源泄漏
- 接受客户端连接后立即关闭
内容的提问来源于stack exchange,提问作者Salim Poui
相关产品推荐
相关产品推荐

