C:套接字连接超时

C:套接字连接超时,c,network-programming,C,Network Programming,我有一个简单的程序来检查端口是否打开,但是我想缩短套接字连接的超时长度,因为默认值太长了。但我不知道该怎么做。代码如下: #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

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

#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;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv){
u_短端口;/*用户指定的端口号*/
char addr[1023];/*将是u输入的地址的副本*/
地址中的struct sockaddr_;/*libc网络地址数据结构*/
网络套接字的short int sock=-1;/*文件描述符*/
如果(argc!=3){
fprintf(标准,“使用率%s”,argv[0]);
返回退出失败;
}
address.sin_addr.s_addr=inet_addr(argv[2]);/*分配地址*/
address.sin_port=htons(atoi(argv[2]);/*translate int2port num*/
sock=socket(AF\u INET,sock\u STREAM,0);
if(connect(sock,(struct sockaddr*)和address,sizeof(address))==0){
printf(“%i打开\n”,端口);
}  
关闭(袜子);
返回0;
}

本文可能有助于:

看起来您将套接字置于非阻塞模式,直到连接完成,然后在连接建立后将其重新置于阻塞模式

void连接到(void){
国际关系;
地址中的结构sockaddr\u;
长精氨酸;
fd_集myset;
结构时间值电视;
int valopt;
socklen_t lon;
//创建套接字
soc=套接字(AF_INET,SOCK_STREAM,0);
如果(soc<0){
fprintf(stderr,“创建套接字(%d%s)时出错)\n”,errno,strerror(errno));
出口(0);
} 
addr.sin_family=AF_INET;
地址:sin_port=htons(2000年);
addr.sin_addr.s_addr=inet_addr(“192.168.0.1”);
//设置非阻塞
如果((arg=fcntl(soc,F_GETFL,NULL))<0){
fprintf(标准,“错误fcntl(…,F_GETFL)(%s)\n”,strerror(errno));
出口(0);
} 
arg |=O|u非块;
如果(fcntl(soc,F_SETFL,arg)<0){
fprintf(标准,“错误fcntl(…,F_SETFL)(%s)\n”,strerror(errno));
出口(0);
} 
//正在尝试连接超时
res=connect(soc,(struct sockaddr*)和addr,sizeof(addr));
如果(res<0){
如果(errno==EINPROGRESS){
fprintf(stderr,“EINPROGRESS in connect()-selection\n”);
做{
tv.tv_sec=15;
tv.tv_usec=0;
FD_ZERO(&myset);
FD_集(soc和myset);
res=选择(soc+1、NULL和myset、NULL和tv);
如果(res<0&&errno!=EINTR){
fprintf(stderr,“连接%d-%s时出错”,errno,strerror(errno));
出口(0);
} 
如果(res>0){
//选择要写入的套接字
lon=sizeof(int);
if(getsockopt(soc,SOL_SOCKET,SO_ERROR,(void*)(&valopt),&lon)<0{
fprintf(stderr,“getsockopt()中的错误%d-%s\n”,errno,strerror(errno));
出口(0);
} 
//检查返回的值。。。
if(valopt){
fprintf(stderr,“延迟连接中的错误()%d-%s\n”,valopt,strerror(valopt)
); 
出口(0);
} 
打破
} 
否则{
fprintf(stderr,“选择中超时()-取消!\n”);
出口(0);
} 
}而(1),;
} 
否则{
fprintf(stderr,“连接%d-%s时出错”,errno,strerror(errno));
出口(0);
} 
} 
//再次设置为阻塞模式。。。
如果((arg=fcntl(soc,F_GETFL,NULL))<0){
fprintf(标准,“错误fcntl(…,F_GETFL)(%s)\n”,strerror(errno));
出口(0);
} 
arg&=(~O_非块);
如果(fcntl(soc,F_SETFL,arg)<0){
fprintf(标准,“错误fcntl(…,F_SETFL)(%s)\n”,strerror(errno));
出口(0);
} 
//我希望就这些
}

将套接字设置为非阻塞,并使用
select()
(它接受一个超时参数)。如果非阻塞套接字正在尝试连接,则
select()
将在
connect()
完成时(成功或失败)指示套接字可写。然后使用
getsockopt()
确定
connect()
的结果:

int main(int argc,char**argv){
u_短端口;/*用户指定的端口号*/
char*addr;/*将是指向地址的指针*/
地址中的struct sockaddr_;/*libc网络地址数据结构*/
网络套接字的short int sock=-1;/*文件描述符*/
fd_集fdset;
结构时间值电视;
如果(argc!=3){
fprintf(stderr,“用法%s\n”,argv[0]);
返回退出失败;
}
端口=atoi(argv[1]);
addr=argv[2];
address.sin_family=AF_INET;
address.sin_addr.s_addr=inet_addr(addr);/*分配地址*/
address.sin_port=htons(port);/*translate int2port num*/
sock=socket(AF\u INET,sock\u STREAM,0);
fcntl(承插式、固定式、非阻塞式);
连接(sock,(struct sockaddr*)和地址,sizeof(address));
FD_零点(&fdset);
FD_套装(袜子和FD套装);
tv.tv_sec=10;/*10秒超时*/
tv.tv_usec=0;
如果(选择(sock+1、NULL和fdset、NULL和tv)==1)
{
int-so_误差;
socklen_t len=so_错误的大小;
getsockopt(sock、SOL_SOCKET、SO_ERROR、&SO_ERROR、&len);
if(so_error==0){
printf(“%s:%d已打开\n”,地址,端口);
}
}
关闭(袜子);
返回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;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv){
str
#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;
}
int synRetries = 2; // Send a total of 3 SYN packets => Timeout ~7s
setsockopt(fd, IPPROTO_TCP, TCP_SYNCNT, &synRetries, sizeof(synRetries));
struct timeval timeout;
timeout.tv_sec  = 7;  // after 7 seconds connect() will timeout
timeout.tv_usec = 0;
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
connect(...)
// Compilation error
setsockopt(fd, SO_SNDTIMEO, &timeout, sizeof(timeout));
// Fixed?
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
struct timeval timeout;
timeout.tv_sec  = 7;  // after 7 seconds connect() will timeout
timeout.tv_usec = 0;
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
connect(...)
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<errno.h>

static void signal_handler(int signo)
{
    return; // Do nothing just interrupt.
}

int main()
{
    /* Register signal handler */

    struct sigaction act, oact;

    act.sa_handler = signal_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

#ifdef SA_INTERRUPT
    act.sa_flags |= SA_INTERRUPT;
#endif

    if(sigaction(SIGALRM, &act, &oact) < 0)  // Error registering signal handler.
    {
        fprintf(stderr, "Error registering signal disposition\n");
        exit(1);
    }

    /* Prepare your socket and sockaddr structures */

    int sockfd;
    struct sockaddr* servaddr;

    /* Implementing timeout connect */

    int sec = 30;

    if(alarm(sec) != 0)
        fprintf(stderr, "Already timer was set\n");

    if(connect(sockfd, servaddr, sizeof(struct sockaddr)) < 0)
    {
        if(errno == EINTR)
            fprintf(stderr, "Connect timeout\n");
        else
            fprintf(stderr, "Connect failed\n");

        close(sockfd);

        exit(1);
    }

    alarm(0);  /* turn off the alarm */

    sigaction(SIGALRM, &oact, NULL);  /* Restore the default actions of SIGALRM */

    /* Use socket */


    /* End program */

    close(sockfd);
    return 0;
}
/* All the code stays */

/* Modifications at connect */

int conn_ret = connect(sockfd, servaddr, sizeof(struct sockdaddr));

if(conn_ret == 0)
    goto done;

/* Modifications at select */

int sec = 30;
for( ; ; )
{
    struct timeval timeo;
    timeo.tv_sec = sec;
    timeo.tv_usec = 0;

    fd_set wr_set, rd_set;
    FDZERO(&wr_set);
    FD_SET(sockfd, &wr_set);
    rd_set = wr_set;
    int sl_ret = select(sockfd + 1, &rd_set, &wr_set, NULL, &timeo);

    /* All the code stays */
}


done:

    /* Use your socket */
#include <sys/socket.h>
#include <fcntl.h>
#include <poll.h>
#include <time.h>

int connect_with_timeout(int sockfd, const struct sockaddr *addr, socklen_t addrlen, unsigned int timeout_ms) {
    int rc = 0;
    // Set O_NONBLOCK
    int sockfd_flags_before;
    if((sockfd_flags_before=fcntl(sockfd,F_GETFL,0)<0)) return -1;
    if(fcntl(sockfd,F_SETFL,sockfd_flags_before | O_NONBLOCK)<0) return -1;
    // Start connecting (asynchronously)
    do {
        if (connect(sockfd, addr, addrlen)<0) {
            // Did connect return an error? If so, we'll fail.
            if ((errno != EWOULDBLOCK) && (errno != EINPROGRESS)) {
                rc = -1;
            }
            // Otherwise, we'll wait for it to complete.
            else {
                // Set a deadline timestamp 'timeout' ms from now (needed b/c poll can be interrupted)
                struct timespec now;
                if(clock_gettime(CLOCK_MONOTONIC, &now)<0) { rc=-1; break; }
                struct timespec deadline = { .tv_sec = now.tv_sec,
                                             .tv_nsec = now.tv_nsec + timeout_ms*1000000l};
                // Wait for the connection to complete.
                do {
                    // Calculate how long until the deadline
                    if(clock_gettime(CLOCK_MONOTONIC, &now)<0) { rc=-1; break; }
                    int ms_until_deadline = (int)(  (deadline.tv_sec  - now.tv_sec)*1000l
                                                  + (deadline.tv_nsec - now.tv_nsec)/1000000l);
                    if(ms_until_deadline<0) { rc=0; break; }
                    // Wait for connect to complete (or for the timeout deadline)
                    struct pollfd pfds[] = { { .fd = sockfd, .events = POLLOUT } };
                    rc = poll(pfds, 1, ms_until_deadline);
                    // If poll 'succeeded', make sure it *really* succeeded
                    if(rc>0) {
                        int error = 0; socklen_t len = sizeof(error);
                        int retval = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
                        if(retval==0) errno = error;
                        if(error!=0) rc=-1;
                    }
                }
                // If poll was interrupted, try again.
                while(rc==-1 && errno==EINTR);
                // Did poll timeout? If so, fail.
                if(rc==0) {
                    errno = ETIMEDOUT;
                    rc=-1;
                }
            }
        }
    } while(0);
    // Restore original O_NONBLOCK state
    if(fcntl(sockfd,F_SETFL,sockfd_flags_before)<0) return -1;
    // Success
    return rc;
}