C:套接字连接超时

我有一个简单的程序来检查一个端口是否打开,但我想缩短套接字连接的超时长度,因为默认太长了。 我不知道如何做到这一点。 代码如下:

#include <sys/socket.h> #include <sys/time.h> #include <sys/types.h> #include <arpa/inet.h> #include <netinet/in.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <netdb.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(int argc, char **argv) { u_short port; /* user specified port number */ char addr[1023]; /* will be a copy of the address entered by u */ struct sockaddr_in address; /* the libc network address data structure */ short int sock = -1; /* file descriptor for the network socket */ if (argc != 3) { fprintf(stderr, "Usage %s <port_num> <address>", argv[0]); return EXIT_FAILURE; } address.sin_addr.s_addr = inet_addr(argv[2]); /* assign the address */ address.sin_port = htons(atoi(argv[2])); /* translate int2port num */ sock = socket(AF_INET, SOCK_STREAM, 0); if (connect(sock,(struct sockaddr *)&address,sizeof(address)) == 0) { printf("%i is open\n", port); } close(sock); return 0; } 

这篇文章可能有帮助: http : //developerweb.net/viewtopic.php?id=3196 。 看起来像是在连接之前将套接字置于非阻塞模式,然后在连接build立后再将其置于阻塞模式。

设置套接字非阻塞,并使用select() (它需要一个超时参数)。 如果一个非阻塞套接字试图连接,那么当connect()完成(成功或失败)时, select()将指示套接字是可写的。 然后使用getsockopt()来确定connect()的结果:

 int main(int argc, char **argv) { u_short port; /* user specified port number */ char *addr; /* will be a pointer to the address */ struct sockaddr_in address; /* the libc network address data structure */ short int sock = -1; /* file descriptor for the network socket */ fd_set fdset; struct timeval tv; if (argc != 3) { fprintf(stderr, "Usage %s <port_num> <address>\n", argv[0]); return EXIT_FAILURE; } port = atoi(argv[1]); addr = argv[2]; address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr(addr); /* assign the address */ address.sin_port = htons(port); /* translate int2port num */ sock = socket(AF_INET, SOCK_STREAM, 0); fcntl(sock, F_SETFL, O_NONBLOCK); connect(sock, (struct sockaddr *)&address, sizeof(address)); FD_ZERO(&fdset); FD_SET(sock, &fdset); tv.tv_sec = 10; /* 10 second timeout */ tv.tv_usec = 0; if (select(sock + 1, NULL, &fdset, NULL, &tv) == 1) { int so_error; socklen_t len = sizeof so_error; getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len); if (so_error == 0) { printf("%s:%d is open\n", addr, port); } } close(sock); return 0; } 

这一个参数化的IP,端口,超时秒,处理连接错误,并给你连接时间以毫秒为单位:

 #include <sys/socket.h> #include <sys/time.h> #include <sys/types.h> #include <arpa/inet.h> #include <netinet/in.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <netdb.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <time.h> int main(int argc, char **argv) { struct sockaddr_in addr_s; char *addr; short int fd=-1; int port; fd_set fdset; struct timeval tv; int rc; int so_error; socklen_t len; struct timespec tstart={0,0}, tend={0,0}; int seconds; if (argc != 4) { fprintf(stderr, "Usage: %s <ip> <port> <timeout_seconds>\n", argv[0]); return 1; } addr = argv[1]; port = atoi(argv[2]); seconds = atoi(argv[3]); addr_s.sin_family = AF_INET; // utilizzo IPv4 addr_s.sin_addr.s_addr = inet_addr(addr); addr_s.sin_port = htons(port); clock_gettime(CLOCK_MONOTONIC, &tstart); fd = socket(AF_INET, SOCK_STREAM, 0); fcntl(fd, F_SETFL, O_NONBLOCK); // setup non blocking socket // make the connection rc = connect(fd, (struct sockaddr *)&addr_s, sizeof(addr_s)); if ((rc == -1) && (errno != EINPROGRESS)) { fprintf(stderr, "Error: %s\n", strerror(errno)); close(fd); return 1; } if (rc == 0) { // connection has succeeded immediately clock_gettime(CLOCK_MONOTONIC, &tend); printf("socket %s:%d connected. It took %.5f seconds\n", addr, port, (((double)tend.tv_sec + 1.0e-9*tend.tv_nsec) - ((double)tstart.tv_sec + 1.0e-9*tstart.tv_nsec))); close(fd); return 0; } /*else { // connection attempt is in progress } */ FD_ZERO(&fdset); FD_SET(fd, &fdset); tv.tv_sec = seconds; tv.tv_usec = 0; rc = select(fd + 1, NULL, &fdset, NULL, &tv); switch(rc) { case 1: // data to read len = sizeof(so_error); getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &len); if (so_error == 0) { clock_gettime(CLOCK_MONOTONIC, &tend); printf("socket %s:%d connected. It took %.5f seconds\n", addr, port, (((double)tend.tv_sec + 1.0e-9*tend.tv_nsec) - ((double)tstart.tv_sec + 1.0e-9*tstart.tv_nsec))); close(fd); return 0; } else { // error printf("socket %s:%d NOT connected: %s\n", addr, port, strerror(so_error)); } break; case 0: //timeout fprintf(stderr, "connection timeout trying to connect to %s:%d\n", addr, port); break; } close(fd); return 0; } 

有关使用select() / poll()的答案是正确的,并且代码应该以这种方式写成可移植的。

但是,因为你在Linux上,你可以这样做:

 int synRetries = 2; // Send a total of 3 SYN packets => Timeout ~7s setsockopt(fd, IPPROTO_TCP, TCP_SYNCNT, &synRetries, sizeof(synRetries)); 

请参阅man 7 tcpman setsockopt

我用它来加快我需要快速修补的程序中的连接超时。 通过select() / poll()其黑屏到超时不是一个选项。