linux下简单的ping程序

来源:互联网 发布:未提交行1中的数据 编辑:程序博客网 时间:2024/06/15 21:33

        简单的整理了一个以前用的ping程序, 个人觉得对初学者学习网络协议还是有一定帮助的,最好是利用抓包工具查看下具体的数据报文。

/* * ping.cpp * *  Created on: Sep 10, 2014 *      Author: xtank.nie@gmail.com */#include <sys/time.h>#include <netinet/ip_icmp.h>#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <string.h>#define SEND_PACKET_NUM (1)int calculate_checksum(unsigned short *packet, int length){    int num_left = length;    int sum = 0;    unsigned short *w = packet;    unsigned short cksum = 0;    while (num_left > 1)    {       sum += *w++;       num_left -= 2;    }    if (num_left == 1)    {        /* 如果是奇数个字节,要在后面补上一个字节的0 */        *((unsigned char *)&cksum) = *((unsigned char *)w);        sum += cksum;    }    sum = (sum>>16) + (sum & 0xffff);    sum += (sum >> 16);    cksum= ~sum;    return cksum;}int crate_icmp_packet(char *packet_buf, uint32_t packet_no){    struct icmp *icmp_st;    int data_size = 56;    int packet_size;    //head    icmp_st = (struct icmp *)packet_buf;    icmp_st->icmp_type = ICMP_ECHO; //请求回送    icmp_st->icmp_code = 0;    icmp_st->icmp_cksum = 0;    icmp_st->icmp_seq = packet_no;    icmp_st->icmp_id = getpid();    //data    gettimeofday((struct timeval *)icmp_st->icmp_data, NULL);    packet_size = 8 + data_size;    icmp_st->icmp_cksum = calculate_checksum((unsigned short *)packet_buf, packet_size);    return packet_size;}int send_packet(int socket_fd, struct sockaddr *addr, char *packet_buf, int packet_no){    int packet_size;    packet_size = crate_icmp_packet(packet_buf, packet_no);    if ((packet_size = sendto(socket_fd, packet_buf, packet_size, 0, addr, sizeof(struct sockaddr_in))) == -1)    {        perror("sendto:");        return (-1); /* error */    }    //printf("send pack size=%d\n", packet_size);    return 0; /* success */}void calculate_interval(struct timeval *recv_time, struct timeval *send_time){    if ((recv_time->tv_usec -= send_time->tv_usec) < 0)    {        recv_time->tv_sec -= 1;        recv_time->tv_usec += 1000000;    }    recv_time->tv_sec -= send_time->tv_sec;}int unpack(struct sockaddr_in *from, char *packet_buf, int packet_size,           struct timeval *recv_time, double *rtt ,unsigned int *ttl){    struct ip *ip_st;    struct icmp *icmp_st;    int ipheader;    ip_st = (struct ip *)packet_buf;    ipheader = (ip_st->ip_hl << 2);    icmp_st = (struct icmp *)(packet_buf + ipheader);    packet_size -= ipheader;    if (packet_size < 8)    {    printf( "recvfrom packet_size < 8!\n");        return (-1); /* error */    }    if ((icmp_st->icmp_type == ICMP_ECHOREPLY) && (icmp_st->icmp_id == getpid()))    {        calculate_interval(recv_time, (struct timeval *)icmp_st->icmp_data);//收到的时间与发送的时间        *rtt = (recv_time->tv_sec * 1000) + (recv_time->tv_usec / 1000);        *ttl = ip_st->ip_ttl;        printf("%d byte from %s: icmp_seq = %u, ttl = %d, rtt = %.3fms\n",               packet_size, inet_ntoa(from->sin_addr), icmp_st->icmp_seq, ip_st->ip_ttl, *rtt);    return 0;    }    else    {        printf( "unpack error! icmp_type is %d, icmp_id is %d\r\n", (icmp_st->icmp_type == ICMP_ECHOREPLY), (icmp_st->icmp_id == getpid()));        return -1;    }}int recv_packet(int socket_fd, char *packet_buf, int *length, double *rtt, unsigned int *ttl){    int nbyte;    struct sockaddr_in from_addr;    struct timeval recv_time;    socklen_t size = sizeof(struct sockaddr_in);    if ((nbyte = recvfrom(socket_fd, packet_buf, *length, 0, (struct sockaddr *)&from_addr, &size)) == -1)    {    printf( "recvfrom return -1!\n" );        return (-1);    }    else    {        ;//printf("recv data len=%d\n", nbyte);    }    *length = nbyte;    gettimeofday(&recv_time, NULL);    if (unpack(&from_addr, packet_buf, nbyte, &recv_time, rtt, ttl) != 0)    {        return (-1);    }    return 0;}int ping(const char *addr){    unsigned long inaddr = 0;    struct sockaddr_in dest_addr;    struct hostent *host;    int socket_ping = -1;    int packet_size = 2048;    char send_pac[2048] = {0};    char recv_pac[2048] = {0};    double iTimespend;    unsigned int iTTL, send_packet_cnt = 0, recv_packet_cnt = 0;;    memset(&dest_addr, 0x0, sizeof(struct sockaddr_in));    dest_addr.sin_family = AF_INET;    if ((inaddr = inet_addr(addr)) == INADDR_NONE)    {        if ((host = gethostbyname(addr)) == NULL)        {            fprintf(stderr, "gethostbyname error.\n");            return -1;        }        memcpy((char *)&(dest_addr.sin_addr), host->h_addr, host->h_length);    }    else    {       dest_addr.sin_addr.s_addr = inaddr;    }    if((socket_ping = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)    {        perror("socket:");        return -1;    }    printf("Ping %s(%s): %d bytes data in ICMP packets.\n", addr, inet_ntoa(dest_addr.sin_addr), 56);    fd_set read_set;    struct timeval timeout;    int i = 1, ret;    for (i = 1; i <=SEND_PACKET_NUM; i++)    {        if (send_packet(socket_ping, (struct sockaddr *)&dest_addr, send_pac, i) == -1)        {            printf("send_packet error\n");            close(socket_ping);            return -1;        }        else        {            ++send_packet_cnt;        }        FD_ZERO(&read_set);        FD_SET(socket_ping, &read_set);        timeout.tv_sec = 1;        timeout.tv_usec = 0;        ret = select(socket_ping+1, &read_set, NULL, NULL, &timeout);        if (ret > 0)        {            if (recv_packet(socket_ping, recv_pac, &packet_size, &iTimespend, &iTTL) == -1)            {                printf("recv_packet error\n");            }            else            {                ++recv_packet_cnt;            }        }        else if (ret == 0)        {              printf("Request time out.\n");              continue;        }        else        {            perror("select error.");            continue;        }    }    close(socket_ping);    //statistics    printf("---- (%s) ping statistics ----\n", addr);    printf("%d packets transmitted, %d received, %d%% packet loss\n",            send_packet_cnt, recv_packet_cnt, (int)(((send_packet_cnt-recv_packet_cnt) * 100)/send_packet_cnt));    return 0;}//quick testint main(int argc, char *argv[]){    if (argc != 2)    {        fprintf(stderr, "Usage: %s [address]\n", argv[0]);        return 0;    }    return ping(argv[1]); }

结合抓包工具就比较容易理解:

执行:sudo ./ping 114.114.114.114


0 0
原创粉丝点击