我正在尝试制作一个简单的 port scanner在C中,终于到了最后阶段。我写了一个简单的函数来连接到端口上的服务器,如果端口关闭,应该会超时。我有以下测试用例:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char **argv) {
if(argc != 3) {
fprintf(stderr, "idiot.\n");
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
int flags = fcntl(sock, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(sock, F_SETFL, flags);
if(sock < 0) {
perror("socket()");
}
struct hostent *server = gethostbyname(argv[1]);
if (server == NULL) {
perror("gethostbyname()");
}
struct sockaddr_in server_addr;
bzero((char*)&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
bcopy(server->h_addr, (char*)&server_addr.sin_addr.s_addr, server->h_length);
server_addr.sin_port = htons(atoi(argv[2]));
if(connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("connecting()");
}
fd_set rfds;
struct timeval tv;
int retval;
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
tv.tv_sec = 3;
tv.tv_usec = 0;
retval = select(sock+1, &rfds, NULL, NULL, &tv);
if (retval == -1)
perror("select()");
else if (retval)
printf("port is open.\n");
else
printf("port is closed.\n");
return 0;
}
问题是,我通过它的任何端口都报告为打开。例如:
[nchambers@shell:~/SpinCloud/Chevron] [devel]$ ./testcase localhost 22 # sshd actually runs on this machine, so its correct
connecting(): Operation now in progress
port is open.
[nchambers@shell:~/SpinCloud/Chevron] [devel]$ telnet localhost 22
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.6
^]
telnet> quit
Connection closed.
[nchambers@shell:~/SpinCloud/Chevron] [devel]$ ./testcase localhost 80 # but no webserver
connecting(): Operation now in progress
port is open.
[nchambers@shell:~/SpinCloud/Chevron] [devel]$ telnet localhost 80
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
[nchambers@shell:~/SpinCloud/Chevron] [devel]$
最佳答案
select
将某些内容报告为“可读”或“可写”的事实仅意味着 read
/write
的尝试不会阻塞.它并不暗示read
/write
的结果 会是什么。
注意:另外,您需要区分 connect
返回 EINPROGRESS
的情况(并轮询这种情况下的可写性)和其他失败。 (虽然也许你可以使用 TCP_KEEPCNT
或 TCP_USER_TIMEOUT
代替?但是如果你像你应该的那样使用 getaddrinfo
并尝试所有地址可能同时出现,但每个地址之间有延迟)
此外,您应该认真考虑使用一种较新的替代方案,如果不是像 epoll
或 这样特定于系统的东西,至少是
.poll
(这是 POSIX) kqueue
关于c - 使用 select() 使套接字超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37370210/