ping代码

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/ip_icmp.h>
#include<netdb.h>
#include<setjmp.h>
#include<errno.h>
#include<string.h>
#include<sys/time.h>

#define MAX_PACKET_SIZE  4096
static int max_packet_num = 4;

char *addr[];
char recv_packet[MAX_PACKET_SIZE];
char send_packet[MAX_PACKET_SIZE];
int sockfd = 0;
int datalen = 56;
int nsend = 0;
int nreceived = 0;
double *temp_rtt = NULL;
double all_time = 0;
double min = 0;
double max = 0;
double avg = 0;
double mdev = 0;

struct sockaddr_in dest_addr;
struct sockaddr_in from_addr;
struct timeval tvrecv;
pid_t pid;

static int pack(int pack_no);
static int unpack(char *buf, int len);

static void compute_rtt() {
    double sum_avg = 0;
    max = min = temp_rtt[0];
    avg = all_time / nreceived;
    int i;
    for(i = 0; i < nreceived; i++) {
        if(temp_rtt[i] < min)
            min = temp_rtt[i];
        if(temp_rtt[i] > max)
            max = temp_rtt[i];
        if(temp_rtt[i] < avg) {
            sum_avg = avg - temp_rtt[i];
        } else {
            sum_avg = temp_rtt[i] - avg;
        }
    }
    mdev = sum_avg / nreceived;
}

static void statistics(int sig) {
    compute_rtt();
    printf("\n----------%s ping statistics-------\n", addr[0]);
    printf("%d packets transmitted, %d packets recevied, %d%% packets lost, time %.f ms\n",
            nsend, nreceived, (nsend - nreceived) / nsend * 100, all_time);
    printf("rtt min/avg/max/mdev = %.3f/%.3f/%.3f/%.3f\n", min, avg, max, mdev);
    close(sockfd);
    exit(1);
}

static unsigned short cal_chsum(unsigned short *addr, int len) {
    int nleft = len;
    int sum = 0;
    unsigned short check_sum = 0;
    unsigned short *w = addr;
    while(nleft > 1) {
        sum += *w++;
        nleft -= 2;
    }
    if(nleft == 1) {
        *(unsigned char*)(&check_sum) = *(unsigned char*)w;
        sum += check_sum;
    }
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    check_sum = ~sum;
    return check_sum;
}

static int pack(int pack_no) {
    int packet_size = 0;
    struct icmp *icmp = NULL;
    struct timeval *tval = NULL;
    icmp = (struct icmp*)send_packet;
    icmp->icmp_type = ICMP_ECHO;
    icmp->icmp_code = 0;
    icmp->icmp_cksum = 0;
    icmp->icmp_seq = pack_no;
    icmp->icmp_id = pid;
    packet_size = 8 + datalen;
    tval = (struct timeval*)icmp->icmp_data;
    gettimeofday(tval, NULL);
    icmp->icmp_cksum = cal_chsum((unsigned short*)icmp, packet_size);
    return packet_size;
}

void sendpacket(void) {
    int packet_size = 0;
    if(nsend < max_packet_num) {
        nsend++;
        packet_size = pack(nsend);
        if(sendto(sockfd, send_packet, packet_size, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) < 0) {
            perror("sendto error!");
        }
    }
}

static void tv_sub(struct timeval *recvtime, struct timeval *sendtime) {
    long sec = recvtime->tv_sec - sendtime->tv_sec;
    long usec = recvtime->tv_usec - sendtime->tv_usec;
    if(usec >= 0) {
        recvtime->tv_sec = sec;
        recvtime->tv_usec = usec;
    } else {
        recvtime->tv_sec -= 1;
        recvtime->tv_usec = -usec;
    }
}


static int unpack(char *buf, int len) {
    int ip_header_len = 0;
    struct ip *ip = NULL;
    struct icmp *icmp = NULL;
    struct timeval *tvsend = NULL;
    double rtt = 0;
    ip = (struct ip*)buf;
    ip_header_len = ip->ip_hl << 2;
    icmp = (struct icmp*)(buf + ip_header_len);
    len -= ip_header_len;
    if(len < 8) {
        printf("ICMP packet\'s length is less than 8.\n");
        return -1;
    }
    if(icmp->icmp_type == ICMP_ECHOREPLY && icmp->icmp_id == pid) {
        tvsend = (struct timeval*)icmp->icmp_data;
        tv_sub(&tvrecv, tvsend);
        rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000;
        temp_rtt[nreceived] = rtt;
        all_time += rtt;
        printf("%d bytes from %s: icmp_seq=%u,ttl=%d,time=%.1f ms\n",
            len, inet_ntoa(from_addr.sin_addr), icmp->icmp_seq, ip->ip_ttl, rtt);
        return 0;
    } else {
        return -1;
    }
}

void recvpacket(void) {
    int n = 0;
    socklen_t addr_len = 0;
    addr_len = sizeof(from_addr);
    if(nreceived < nsend) {
        n = recvfrom(sockfd, recv_packet, sizeof(recv_packet), 0, (struct sockaddr*)&from_addr, &addr_len);
        if(n < 0) {
            perror("recvfrom error!");
        }
        gettimeofday(&tvrecv, NULL);
        unpack(recv_packet, n);
        nreceived++;
    }
}

int main(int argc, char *argv[]) {
    int i = 0;
    struct hostent *host = NULL;
    struct protoent *protocol = NULL;
    int size = 50 * 1024;
    addr[0] = argv[1];
    if(argc < 2) {
        printf("usage: %s hostname/IP address.\n", argv[0]);
        exit(-1);
    }
    for(i = 0; i < argc; i++) {
        if(strcmp(argv[i], "-t") == 0)
            sscanf(argv[i+1], "%d", &max_packet_num);
    }
    temp_rtt = (double*)malloc(sizeof(double) * max_packet_num);
    bzero(temp_rtt, sizeof(double) * max_packet_num);
    if((protocol = getprotobyname("icmp")) == NULL) {
        perror("getprotobyname");
        exit(-1);
    }
    //create raw socket need root, use sudo ./myping www.baidu.com
    if((sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0) {
        perror("socket error");
        exit(-1);
    }
    setuid(getuid());
    setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
    bzero(&dest_addr, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    if(inet_addr(argv[1]) == INADDR_NONE) {
        if((host = gethostbyname(argv[1])) == NULL) {
            perror("gethostbyname error!");
            exit(-1);
        }
        memcpy((char*)(&dest_addr.sin_addr), host->h_addr, host->h_length);

    } else {
        dest_addr.sin_addr.s_addr = inet_addr(argv[1]);
    }
    pid = getpid();
    printf("ping %s(%s):%d bytes of data.\n", argv[1], inet_ntoa(dest_addr.sin_addr), datalen);
    signal(SIGINT, statistics);
    while(nsend < max_packet_num){
        sleep(1);
        sendpacket();
        recvpacket();
    }
    if(nsend == max_packet_num) {
       statistics(0);
    }
    free(temp_rtt);
    return 0;
}


测试用例: sudo ./myping www.baidu.com -t 6

目前只支持 -t这个参数,其他的还没有实现。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值