Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用select()对套接字进行超时_C_Sockets_Select - Fatal编程技术网

使用select()对套接字进行超时

使用select()对套接字进行超时,c,sockets,select,C,Sockets,Select,我试图用C语言做一个简单的测试,现在终于到了最后阶段。我编写了一个简单的函数来连接端口上的服务器,如果端口关闭,应该超时。我有以下测试用例: #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <fcntl.h> #in

我试图用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;
}

select
将某些内容报告为“可读”或“可写”,这一事实仅意味着尝试
/
不会被阻止。它并不意味着
读取
/
写入
的结果会是什么

注意:此外,您还需要将
connect
返回
EINPROGRESS
(并在该情况下轮询可写性)的情况与其他故障区分开来。(虽然您可能可以使用
TCP\u keepnt
TCP\u USER\u TIMEOUT
来代替?但如果您像预期的那样使用
getaddrinfo
并尝试所有地址,但每个地址之间都有一个延迟,那么这就行不通了)


此外,您应该认真考虑使用一种较新的替代方案,至少<代码> Poope<代码>(即POSIX),如果没有特定的系统类型,如<代码> EPOLIO/COD>或<代码> KQue>/Calp>。< /P> < p>打开非阻塞请求。调用connect()时,它返回

EINPROGRESS
,或“操作正在进行”,如中所述:

您应该检查connect()上的
errno
值。此外,非负的
select
返回并不一定意味着您正在测试的服务器上的端口是打开的

另外,您发布的代码通常不能很好地处理错误。从第一个
if(argc!=3){
,您不返回,只打印一条消息。如果您在没有三个输入的情况下运行代码,它将显示错误,但随后继续执行(这可能会导致seg错误)


我鼓励您花更多时间研究同步与异步I/o,并在假设端口打开之前实际连接到端口。

@DTSCode阅读所有手册页是一个很好的开始,其中有很多。
[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]$
          The socket is nonblocking and the connection cannot be
          completed immediately.  It is possible to select(2) or poll(2)
          for completion by selecting the socket for writing.  After
          select(2) indicates writability, use getsockopt(2) to read the
          SO_ERROR option at level SOL_SOCKET to determine whether
          connect() completed successfully (SO_ERROR is zero) or
          unsuccessfully (SO_ERROR is one of the usual error codes
          listed here, explaining the reason for the failure).