zoukankan      html  css  js  c++  java
  • 网络超时检测方法

    超时检测的必要性:避免进程在没有数据时无限制地阻塞,当设定的时间到时,进程从原操作返回继续运行。

    方法(1):使用setsockopt函数

    时间结构体 struct timeval  tv;

    可设定

    tv.tv_sec = 5; // 设置5秒时间
    tv.tv_usec = 0;

    然后设置超时选项

    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

    注意:将进程中和sockfd相关的阻塞,变为非阻塞。

    实例代码:

    server.c

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<sys/types.h>
     4 #include<sys/socket.h>
     5 #include<unistd.h>
     6 #include<netinet/in.h>
     7 #include<arpa/inet.h>
     8 #include<string.h>
     9 #include<errno.h>
    10 
    11 #define N 64
    12 #define err_log(log) do{ perror(log); exit(1);}while(0)
    13     
    14 int main(int argc, const char *argv[])
    15 {
    16     int sockfd, connectfd;
    17     char buf[N];
    18     struct sockaddr_in serveraddr, clientaddr;
    19     socklen_t len = sizeof(clientaddr);
    20     struct timeval tv;
    21     socklen_t optlen = sizeof(tv);
    22 
    23     if(argc != 3)
    24     {
    25         fprintf(stderr, "Usage:%s serverip port", argv[0]);
    26         return -1;
    27     }
    28 
    29     sockfd = socket(AF_INET, SOCK_STREAM, 0);
    30     if(sockfd < 0)
    31         err_log("fail to sockfd");
    32 
    33     serveraddr.sin_family = AF_INET;
    34     serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    35     serveraddr.sin_port = htons(atoi(argv[2]));
    36 
    37     tv.tv_sec = 5;
    38     tv.tv_usec = 0;
    39     if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, optlen) < 0)
    40         err_log("fail to setsockopt");
    41 
    42     if(bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
    43         err_log("fail to bind");
    44 
    45     if(listen(sockfd, 5) < 0)
    46         err_log("fail to listen");
    47 
    48     if((connectfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len)) < 0)
    49     {
    50         if(errno == 11)
    51         {
    52             printf("errno = %d--->%s
    ", errno, strerror(errno));
    53         }
    54         else
    55         {
    56             err_log("fail to accept");
    57         }
    58     }
    59     printf("client:%s--->%d
    ", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    60     while(1)
    61         {
    62             if(recv(connectfd, buf, N, 0) < 0)
    63                 err_log("fail to recv");
    64             if(strncmp(buf, "quit", 4) == 0)
    65                 break;
    66             buf[strlen(buf) - 1] = '';
    67             printf("buf:%s
    ", buf);
    68         }
    69     close(connectfd);
    70     close(sockfd);
    71     return 0;
    72 }

    client.c

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<sys/types.h>
     4 #include<sys/socket.h>
     5 #include<unistd.h>
     6 #include<arpa/inet.h>
     7 #include<netinet/in.h>
     8 #include<string.h>
     9 #include<errno.h>
    10 
    11 #define N 64
    12 #define err_log(log) do{perror(log); exit(1);}while(0)
    13 int main(int argc, const char *argv[])
    14 {
    15     int sockfd;
    16     char buf[N];
    17     struct sockaddr_in serveraddr;
    18 
    19     if(argc != 3)
    20     {
    21         fprintf(stderr, "Usage:%s serverip port.", argv[0]);
    22         return -1;
    23     }
    24 
    25     sockfd = socket(AF_INET, SOCK_STREAM, 0);
    26     if(sockfd < 0)
    27         err_log("fail to sockfd");
    28 
    29     serveraddr.sin_family = AF_INET;
    30     serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    31     serveraddr.sin_port = htons(atoi(argv[2]));
    32 
    33     if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
    34         err_log("fail to connect");
    35 
    36     while(1)
    37     {
    38         printf("<client>");
    39         fgets(buf, N, stdin);
    40         if(send(sockfd, buf, N, 0) < 0)
    41             err_log("fail to send");
    42         if(strncmp(buf, "quit", 4) == 0)
    43             break;
    44         printf("buf:%s
    ", buf);
    45     }
    46     close(sockfd);
    47     return 0;
    48 }

    方法(2)使用select函数

    时间结构体 struct timeval  tv;

    可设定

    tv.tv_sec = 5; // 设置5秒时间
    tv.tv_usec = 0;

    select(sockfd, maxfd+1, &readfds, NULL, NULL, &tv);

    注意:每次超时检测执行完毕之后,tv就会被清零,需要重新赋值。

    示例代码:

    server.c

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<sys/types.h>
     4 #include<sys/socket.h>
     5 #include<arpa/inet.h>
     6 #include<netinet/in.h>
     7 #include<string.h>
     8 #include<fcntl.h>
     9 #include<unistd.h>
    10 #include<sys/select.h>
    11 #include<sys/time.h>
    12 
    13 #define N 64
    14 int main(int argc, const char *argv[])
    15 {
    16     int sockfd, connectfd, maxfd;
    17     char buf[N];
    18     struct sockaddr_in serveraddr, clientaddr;
    19     fd_set readfds;
    20     socklen_t len = sizeof(clientaddr);
    21     struct timeval tv;
    22     int ret, i = 0;
    23 
    24     if(argc != 3)
    25     {
    26         fprintf(stderr, "Usage:%s serverip port", argv[1]);
    27         return -1;
    28     }
    29     sockfd = socket(AF_INET, SOCK_STREAM, 0);
    30     if(sockfd < 0)
    31     {
    32         perror("fail to sockfd");
    33         return -1;
    34     }
    35     serveraddr.sin_family = AF_INET;
    36     serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    37     serveraddr.sin_port = htons(atoi(argv[2]));
    38     if(bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
    39     {
    40         perror("fail to bind");
    41         return -1;
    42     }
    43     if(listen(sockfd, 5) < 0)
    44     {
    45         perror("fail to listen");
    46         return -1;
    47     }
    48     printf("sockfd = %d
    ", sockfd);
    49     maxfd = sockfd;
    50     while(1)
    51     {
    52         FD_ZERO(&readfds);
    53         FD_SET(0, &readfds);
    54         FD_SET(sockfd, &readfds);
    55 
    56         tv.tv_sec = 5;
    57         tv.tv_usec = 0;
    58 
    59         ret = select(maxfd + 1, &readfds, NULL, NULL, &tv);
    60         switch(ret)
    61         {
    62         case -1:
    63             perror("fail to select");
    64             break;
    65         case 0:
    66             printf("timeout--->ret = %d
    ", ret);
    67             break;
    68         default:
    69             for(i = 0; i < maxfd + 1; i++)
    70             {
    71                 if(FD_ISSET(i, &readfds))
    72                 {
    73                     if(i == 0)
    74                     {
    75                         read(i, buf, N);
    76                         printf("buf:%s
    ", buf);
    77                     }
    78                     else
    79                     {
    80                         if((connectfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len)) < 0)
    81                         {
    82                             perror("fail to connectfd");
    83                             return -1;
    84                         }
    85                         printf("client:%s--->%d
    ", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    86                         close(connectfd);
    87                     }
    88                 }
    89             }
    90         }
    91     }
    92     return 0;
    93 }

    cient.c

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<sys/types.h>
     4 #include<sys/socket.h>
     5 #include<arpa/inet.h>
     6 #include<netinet/in.h>
     7 #include<string.h>
     8 #include<fcntl.h>
     9 #include<unistd.h>
    10 
    11 #define N 64
    12 int main(int argc, const char *argv[])
    13 {
    14     int sockfd;
    15     struct sockaddr_in serveraddr;
    16 
    17     if(argc != 3)
    18     {
    19         fprintf(stderr, "Usage:%s serverip port.", argv[0]);
    20         return -1;
    21     }
    22     sockfd = socket(AF_INET, SOCK_STREAM, 0);
    23     if(sockfd < 0)
    24     {
    25         perror("fail to sockfd");
    26         return -1;
    27     }
    28     serveraddr.sin_family = AF_INET;
    29     serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    30     serveraddr.sin_port = htons(atoi(argv[2]));
    31     if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
    32     {
    33         perror("fail to connect");
    34         return -1;
    35     }
    36     printf("client exit...
    ");
    37     close(sockfd);
    38     return 0;
    39 }

    方法(3)使用sigaction函数

    示例代码:

    server.c

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<sys/types.h>
     4 #include<sys/socket.h>
     5 #include<string.h>
     6 #include<signal.h>
     7 #include<netinet/in.h>
     8 #include<arpa/inet.h>
     9 #include<unistd.h>
    10 #include<errno.h>
    11 #include<fcntl.h>
    12 
    13 #define N 64
    14 #define err_log(log) do{ perror(log); exit(1);}while(0)
    15 void handler(int signo)
    16 {
    17     printf("timeout.
    ");
    18 }
    19 int main(int argc, const char *argv[])
    20 {
    21     int sockfd, connectfd;
    22     char buf[N];
    23     struct sockaddr_in serveraddr, clientaddr;
    24     struct sigaction act;
    25     socklen_t len = sizeof(clientaddr);
    26 
    27     if(argc != 3)
    28     {
    29         fprintf(stderr, "Usage:%s serverip port.", argv[0]);
    30         return -1;
    31     }
    32 
    33     sockfd = socket(AF_INET, SOCK_STREAM, 0    );
    34     if(sockfd < 0)
    35         err_log("fail to sockfd");
    36 
    37     serveraddr.sin_family = AF_INET;
    38     serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    39     serveraddr.sin_port = htons(atoi(argv[2]));
    40 
    41     if(bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
    42         err_log("fail to bind");
    43 
    44     if(listen(sockfd, 5) < 0)
    45         err_log("fail to listen");
    46 
    47     printf("sockfd = %d
    ", sockfd);
    48 
    49     sigaction(SIGALRM, NULL, &act);
    50     act.sa_handler = handler;
    51     act.sa_flags &= ~SA_RESTART;
    52     sigaction(SIGALRM, &act, NULL);
    53 
    54     memset(&clientaddr, 0, sizeof(clientaddr));
    55 
    56     if((connectfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len)) < 0)
    57     {
    58         if(errno == 4)
    59         {
    60             printf("errno = %d--->%s
    ", errno, strerror(errno));
    61         }
    62         else
    63         {
    64             err_log("fail to accept");
    65         }
    66     }
    67 
    68     printf("client:%s--->%d
    ", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    69     while(1)
    70     {
    71         alarm(5);
    72         if(recv(connectfd, buf, N, 0) < 0)
    73         {
    74             if(errno == 4)
    75             {
    76                 printf("errno = %d--->%s
    ", errno, strerror(errno));
    77             }
    78             else
    79             {
    80                 err_log("fail to recv");
    81             }
    82         }
    83 
    84         if(recv(connectfd, buf, N, 0) < 0)
    85         {
    86             if(errno == 4)
    87             {
    88                 printf("errno = %d--->%s
    ", errno, strerror(errno));
    89             }
    90             else
    91             {
    92                 err_log("fail to recv");
    93             }
    94         }
    95 
    96     }
    97     close(connectfd);
    98     return 0;
    99 }

    client.c

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<sys/types.h>
     4 #include<sys/socket.h>
     5 #include<unistd.h>
     6 #include<string.h>
     7 #include<arpa/inet.h>
     8 #include<netinet/in.h>
     9 
    10 #define N 64
    11 #define err_log(log) do{perror(log); exit(1);}while(0)
    12 int main(int argc, const char *argv[])
    13 {
    14     int sockfd;
    15     struct sockaddr_in serveraddr;
    16     char buf[N];
    17 
    18     if(argc != 3)
    19     {
    20         fprintf(stderr, "Usage:%s serverip port", argv[0]);
    21         return -1;
    22     }
    23 
    24     sockfd = socket(AF_INET, SOCK_STREAM, 0);
    25     if(sockfd < 0)
    26         err_log("fail to sockfd");
    27 
    28     serveraddr.sin_family = AF_INET;
    29     serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    30     serveraddr.sin_port = htons(atoi(argv[2]));
    31 
    32     if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
    33         err_log("fail to connect");
    34 
    35     while(1)
    36     {
    37         printf("<client>");
    38         fgets(buf, N, stdin);
    39         if(send(sockfd, buf, N, 0) < 0)
    40             err_log("fail to send");
    41     }
    42     printf("client exit...
    ");
    43     close(sockfd);
    44     return 0;
    45 }

    对于sa_flags选项的SA_RESTART是自重启属性,默认为真。

    注意:

    SA_RESTART 自重启属性为真。进程执行时,信号产生了,执行信号处理函数,处理完毕之后,回到程序原来的地方,接着往下执行。

    当进程正在执行系统调用(阻塞),此时信号产生了,执行信号处理函数,完毕之后,回到进程原来执行的地方(系统调用)继续执行,那么又来执行系统调用就阻塞。不能实现超时检测。

    自重启属性为假,当进程正在执行系统调用(阻塞),此时信号产生了,执行信号处理函数,完毕之后,回到进程原来执行的地方(系统调用),
    系统调用失败了,进程向下执行(不阻塞)。

    alarm() 函数,只对它后面的第一个正在发生阻塞的函数有效,使其不阻塞。

  • 相关阅读:
    C# DataTable的詳細用法 .
    webgl复习笔记——纹理装配
    webgl复习笔记——图形装配过程
    webgl复习笔记——三角形平移、旋转(2)
    webgl复习笔记——[回顾]从零绘制三角形
    webgl复习笔记——三角形平移、旋转(1)
    webgl复习笔记——绘制三角形、四边形
    webgl复习笔记——通过arraybuffer绘制多个点
    webgl复习笔记——可以自由设置颜色的点
    webgl复习笔记——绘制 点、多个点
  • 原文地址:https://www.cnblogs.com/yangziwen0709/p/5026158.html
Copyright © 2011-2022 走看看