• 003.同时Ping多个IP(select实现IO复用,信号计时),ping程序升级版


    写这个的目的主要是为了以后的方便:

    1.信号计时函数的使用

    2.ip头的构建和icmp头的构建

    3.selec函数t的用法

    代码实现:

    /src/ping.h

     1 /*
     2  * ping.h
     3  *
     4  *  Created on: 2015年11月6日
     5  *      Author: root
     6  */
     7 
     8 #ifndef PING_H_
     9 #define PING_H_
    10 
    11 #endif /* PING_H_ */
    12 
    13 #include <sys/types.h>
    14 #include <sys/select.h>
    15 #include <stdio.h>
    16 #include <string.h>
    17 #include <netdb.h>
    18 #include <arpa/inet.h>
    19 #include <unistd.h>
    20 #include <signal.h>
    21 #include <sys/time.h>
    22 #include <sys/socket.h>
    23 #include <netinet/ip_icmp.h>
    24 #include<errno.h>    /*sys/types.h中文名称为基本系统数据类型*/
    25 
    26 #define N 200005
    27 #define PACKET_SIZE 1024*4
    28 
    29 extern FILE *out;
    30 extern int nsent;
    31 extern int nrecv;
    32 
    33 extern char * intip_to_ipv4(unsigned int ip);
    34 extern void recv_all_packet(int sockfd);
    35 extern int send_one_packet(int sockfd, unsigned int ip_num, int pid);
    /src/ping.h

    /src/ping_project.c

      1 /*
      2  ============================================================================
      3  Name        : ping_project.c
      4  Author      : huh
      5  Version     :
      6  Copyright   : ---notice---
      7  Description : Hello World in C, Ansi-style
      8  ============================================================================
      9  */
     10 
     11 #include "ping.h"
     12 
     13 FILE *out;
     14 
     15 int pid;
     16 int the_number_of_ping = 0;
     17 int send_sockfd, recv_sockfd;
     18 int ping_num = 0;  //ip地址数量
     19 unsigned int addr[N];  //ip地址数组
     20 struct sigaction act_alarm;
     21 struct timeval timeout;
     22 struct itimerval val_alarm ={
     23         .it_interval.tv_sec = 1,
     24         .it_interval.tv_usec = 0,
     25         .it_value.tv_sec = 0,
     26         .it_value.tv_usec = 1 };
     27 fd_set init_recv_sockets, recv_sockets;
     28 fd_set init_send_sockets, send_sockets, init_send_sockets_2;
     29 
     30 int size = 1024 * 50;
     31 
     32 void init_ip();
     33 void sig_alrm(int singo);
     34 
     35 int main(void)
     36 {
     37     init_ip();
     38     out = fopen("./src/file/a.out", "w");
     39     if (out == NULL)
     40     {
     41         perror("stdout error!
    ");
     42     }
     43     int flag1, flag2;
     44     pid = getpid();
     45     send_sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
     46     //if(send_sockfd < 0)    {        perror("send_sockfd error:");        return 0;    }
     47     flag1 = setsockopt(send_sockfd, IPPROTO_IP, IP_HDRINCL, &size,
     48             sizeof(size));
     49     //if(flag1<0)     {        perror("setsockopt error:");        return 0;    }
     50     recv_sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
     51     //if(recv_sockfd < 0)    {        perror("recv_sockfd error:");        return 0;    }
     52     flag2 = setsockopt(recv_sockfd, IPPROTO_IP, IP_HDRINCL, &size,
     53             sizeof(size));
     54     //if(flag2<0)     {        perror("setsockopt error:");        return 0;    }
     55 
     56     act_alarm.sa_handler = sig_alrm;
     57     if (sigaction(SIGALRM, &act_alarm, NULL) == -1)
     58         printf("SIGALRM handler setting fails.
    ");
     59 
     60     if ((setitimer(ITIMER_REAL, &val_alarm, NULL)) == -1) /*定时函数*/
     61         printf("setitimer fails.
    ");
     62 
     63     int result;
     64     int maxfdp1;
     65     int k = 0;
     66 
     67     FD_ZERO(&init_recv_sockets);
     68     FD_SET(recv_sockfd, &init_recv_sockets);
     69 
     70     FD_ZERO(&init_send_sockets);
     71     FD_SET(send_sockfd, &init_send_sockets);
     72     init_send_sockets_2 = init_send_sockets;
     73 
     74     maxfdp1 = recv_sockfd + 1;
     75     while (1) //无限循环,接受包
     76     {
     77         recv_sockets = init_recv_sockets;
     78         send_sockets = init_send_sockets_2;
     79         timeout.tv_sec = 1;
     80         timeout.tv_usec = 500000;
     81         result = select(maxfdp1, &recv_sockets, &send_sockets, NULL, &timeout);
     82         switch (result)
     83         {
     84         case 0:
     85             printf("共发送了%d个包, 收到了%d个包
    ", nsent, nrecv);
     86             printf("timeout:程序结束!
    ");
     87             return 0;
     88             break;
     89         case -1:
     90             if (errno == EINTR)
     91                 continue;
     92             perror("select:");
     93             return 0;
     94             break;
     95         default:
     96             if (FD_ISSET(recv_sockfd, &recv_sockets))
     97                 recv_all_packet(recv_sockfd);
     98             if (FD_ISSET(send_sockfd, &send_sockets))
     99             {
    100                 send_one_packet(send_sockfd, addr[k], pid);
    101                 k = (k + 1) % ping_num;
    102                 if (k == 0)
    103                     FD_ZERO(&init_send_sockets_2);
    104             }
    105             break;
    106         }
    107     }
    108     return 0;
    109 }
    110 
    111 void sig_alrm(int singo)
    112 {
    113     the_number_of_ping++;
    114     if (the_number_of_ping <= 30)
    115     {
    116         printf("ping了第%d遍!
    ", the_number_of_ping);
    117         init_send_sockets_2 = init_send_sockets;
    118     } else
    119     {
    120         val_alarm.it_interval.tv_sec = 0;
    121         val_alarm.it_interval.tv_usec = 0;
    122         val_alarm.it_value = val_alarm.it_interval;
    123         setitimer(ITIMER_REAL, &val_alarm, NULL);
    124     }
    125 }
    126 
    127 void init_ip()  //将要访问的主机全部变成32位无符号的ip。
    128 {
    129     FILE *in;
    130     unsigned int name;
    131     char str[55];
    132     struct hostent *host;
    133 
    134     in = freopen("./src/file/a.in", "r", stdin);
    135     if (in == NULL)
    136     {
    137         printf("stdin error!
    ");
    138     }
    139 
    140     while (!feof(in))
    141     {
    142         scanf("%s", str);  //ip地址或域名
    143         name = inet_addr(str);  //将一个点分十进制IP转化为长整数
    144         if (name == INADDR_NONE)
    145         {
    146             host = gethostbyname(str);
    147             if (host == NULL)
    148             {
    149                 printf("参数格式不正确,请重新输入!
    ");
    150                 continue;
    151             }
    152             memcpy((char*) &name, host->h_addr, 4);
    153         }
    154         addr[ping_num] = name;
    155         printf("%s:%s
    ", str, intip_to_ipv4(name));
    156         ping_num++;
    157     }
    158     printf("程序将 ping %d 个IP.
    ", ping_num);
    159 }
    /src/ping_project.c

    /src/send.c

     1 /*
     2  * send.c
     3  *
     4  *  Created on: 2015年11月6日
     5  *      Author: root
     6  */
     7 
     8 #include "ping.h"
     9 
    10 int icmp_len;
    11 int flag;
    12 int nsent=0;
    13 int datalen = 56;
    14 struct icmp *icmp;
    15 char sendbuf[PACKET_SIZE];
    16 struct sockaddr_in dest_addr; //socket目的地址
    17 
    18 unsigned short cal_chksum(unsigned short *addr, int len)
    19 {
    20     int nleft = len;
    21     int sum = 0;
    22     unsigned short *w = addr;
    23     unsigned short answer = 0;
    24     //把ICMP报头二进制数据以2字节为单位累加起来
    25     while (nleft > 1)
    26     {
    27         sum += *w++;
    28         nleft -= 2;
    29     }
    30     if (nleft == 1)
    31     {
    32         *(unsigned char *)(&answer) = *(unsigned char *)w;
    33         sum += answer;
    34     }
    35     sum = (sum>>16) + (sum&0xffff);
    36     sum += (sum>>16);
    37     answer = ~sum;
    38     return answer;
    39 }
    40 
    41 char * intip_to_ipv4(unsigned int ip)
    42 {
    43     char *str;
    44     struct in_addr des;
    45     des.s_addr = ip;
    46     str = inet_ntoa(des);
    47     //printf("---%s---
    ",str);
    48     return str;
    49 }
    50 
    51 int send_one_packet(int sockfd, unsigned int ip_num, int pid)
    52 {
    53     struct iphdr *ip;
    54     ip = (struct iphdr *)sendbuf;
    55     ip->ihl = sizeof(struct iphdr) >> 2; //首部长度
    56     ip->version = 4; //ip协议版本
    57     ip->tos = 0; //服务类型字段
    58     ip->tot_len = 84; //总长度
    59     ip->id = 0;
    60     ip->frag_off = 0;
    61     ip->ttl = 255;
    62     ip->protocol = IPPROTO_ICMP;
    63     ip->check = 0;  //让内核算
    64 
    65     dest_addr.sin_family = AF_INET;
    66     memcpy((char *)&dest_addr.sin_addr, (char *)&ip_num,sizeof(ip_num));
    67     //ip->saddr = src_addr.sin_addr.s_addr;
    68     ip->daddr = dest_addr.sin_addr.s_addr;
    69 
    70     icmp = (struct icmp *)(sendbuf + sizeof(struct iphdr));
    71     icmp->icmp_type = ICMP_ECHO;  //拼接icmp
    72     icmp->icmp_code = 0;
    73     icmp->icmp_id = pid;   //2字节
    74     icmp->icmp_seq = ++nsent; //2字节
    75     memset(icmp->icmp_data, 0xa5, datalen);
    76     gettimeofday((struct timeval *)icmp->icmp_data, NULL);    //将发送时间作为数据传递过去
    77 
    78     icmp_len = datalen + 8;
    79     icmp->icmp_cksum = 0;
    80     icmp->icmp_cksum = cal_chksum((unsigned short *)icmp, icmp_len);
    81 
    82     flag = sendto(sockfd, sendbuf, ip->tot_len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));  //将包发出去
    83     //if(flag < 0) {    printf("sendto error!
    ");    return 0; }
    84 
    85     fprintf(out,"inet addr:%s 's packet have sent!
    ",intip_to_ipv4(ip_num));
    86     return 0;
    87 }
    /src/send.c

    /src/recv.c

     1 /*
     2  * recv.c
     3  *
     4  *  Created on: 2015年11月6日
     5  *      Author: root
     6  */
     7 
     8 #include "ping.h"
     9 
    10 int nrecv=0;
    11 struct timeval tvrecv;
    12 char recvbuf[PACKET_SIZE];
    13 struct sockaddr_in src_addr; //socket源地址
    14 
    15 int len;  //统计收到的包的长度
    16 int src_addr_len = sizeof(struct sockaddr_in);
    17 
    18 void tv_sub(struct timeval *out,struct timeval *in)
    19 {
    20     if ((out->tv_usec-=in->tv_usec) < 0)
    21     {
    22         --out->tv_sec;
    23         out->tv_usec += 1000000;
    24     }
    25     out->tv_sec -= in->tv_sec;
    26 }
    27 
    28 void unpacket(int sockfd, int len,int pid)
    29 {
    30     //int len;
    31     double rtt;
    32     int iphdrlen;
    33     struct ip *ip;
    34     struct icmp *icmp;
    35     struct timeval *tvsend;
    36 
    37     gettimeofday(&tvrecv,NULL);
    38     ip = (struct ip *)recvbuf;
    39     iphdrlen = ip->ip_hl<<2;
    40     //printf("%d
    ",iphdrlen);
    41     icmp = (struct icmp *)(recvbuf+iphdrlen);
    42     len -= iphdrlen;
    43 
    44     if((icmp->icmp_type == ICMP_ECHOREPLY) && (icmp->icmp_id == pid))
    45     {
    46         tvsend = (struct timeval *)icmp->icmp_data;
    47         tv_sub(&tvrecv, tvsend);//接收和发送的时间差
    48         rtt = tvrecv.tv_sec*1000.0 + (1.0*tvrecv.tv_usec)*0.001;//以毫秒单位计算rtt
    49         fprintf(out,"%d byte from %s: icmp_seq=%u ttl=%d rtt=%.3f ms
    ", len, inet_ntoa(ip->ip_src), icmp->icmp_seq, ip->ip_ttl, rtt);
    50         nrecv++;
    51     }
    52     //sleep(1);
    53 }
    54 
    55 void recv_all_packet(int recv_sockfd)
    56 {
    57     len = recvfrom(recv_sockfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&src_addr, (socklen_t *)&src_addr_len);
    58     if(len < 0)
    59         perror("recvfrom:");
    60     unpacket(recv_sockfd, len, getpid());
    61     return ;
    62 }
    /src/recv.c

    /src/file/a.in

     1 www.baidu.com
     2 www.qq.com
     3 www.jd.com
     4 www.aminglinux.com
     5 map.baidu.com
     6 music.baidu.com
     7 image.baidu.com
     8 zhidao.baidu.com
     9 www.tmall.com
    10 127.0.0.1
    /src/file/a.in
  • 相关阅读:
    深入Java微服务之网关系列1:什么是网关
    logstash系列快速调试demo
    logstash系列input和output方案预研结果
    99zeppelin使用和一些预研
    filebeat系列如何给日志增加一些额外的标记字段
    filebeat系列快速调试demo
    logstash系列使用中的一些点
    Redis常用命令
    springboot使用外置tomcat
    Redis持久化和事务
  • 原文地址:https://www.cnblogs.com/ruo-yu/p/4979003.html
Copyright © 2020-2023  润新知