使用select()对套接字进行超时
我试图用C语言做一个简单的测试,现在终于到了最后阶段。我编写了一个简单的函数来连接端口上的服务器,如果端口关闭,应该超时。我有以下测试用例:使用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
#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).