c - 使用 select() 使套接字超时

标签 c sockets select

我正在尝试制作一个简单的 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_KEEPCNTTCP_USER_TIMEOUT 代替?但是如果你像你应该的那样使用 getaddrinfo 并尝试所有地址可能同时出现,但每个地址之间有延迟)

此外,您应该认真考虑使用一种较新的替代方案,如果不是像 epoll 这样特定于系统的东西,至少是 poll(这是 POSIX) kqueue.

关于c - 使用 select() 使套接字超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37370210/

相关文章:

c - 如何清除 Char 数组中的特定元素

c - 使用 qsort 对无符号整数进行排序

c++ - 通过连续两次调用 boost::asio::read 检索正确的数据

python - 客户端-使用python进行服务器套接字编程

c++ - 模拟模板的 C 错误

从 linux 主机控制 Jabra 710 USB 扬声器音量

java - socket.accept() 不执行

php - 如何从两个不同的表中进行 SELECT 和 COUNT 以在一个查询中获取帖子的 "like count"?

Mysql更新+SELECT查询

php - 如何从两个表中选择数据,其中第一个表的一行仅选择第二个表的第一行