C/C++ ping

第一篇博客,参考大神代码,整理思路写的。

#include "sys/socket.h"
#include "sys/types.h"
#include "stdio.h"
#include "stdlib.h"
#include "netdb.h"
#include "sys/time.h"
#include "time.h"
#include "unistd.h"
#include "arpa/inet.h"
#include "netinet/in.h"
#include "signal.h"
#include "string.h"
#define BUF_SIZE 1024*1024
#define TIMEOUT 2
#define INF 1<<30
struct IPHEADER{
    unsigned char ver_hlen;
    unsigned char tos;
    unsigned short dlen;
    unsigned short id;
    unsigned short flag_index;
    unsigned char ttl;
    unsigned char proto;
    unsigned short checksum;
    unsigned int src;
    unsigned int dest;
    unsigned int add[0];
};
struct ICMPHEADER{
    unsigned char type;
    unsigned char code;
    unsigned short checksum;
    unsigned short id;
    unsigned short seq;
};
//var
timeval start,end;
int sock_raw;
timeval st,rt,timeout;
char sendbuf[BUF_SIZE],recvbuf[BUF_SIZE];
int ptime=4;
hostent* ht;
sockaddr_in dest;
const int SOCK_DEFAULT_BUFSIZE=32*1024;
int cnt=0,pn=0;
//
int init(int argc,char*argv[]){
    if(argc<2){
        printf("no enough arg!\n");
        return -1;
    }else if(argc==3){
        if(*(argv[2]+1)=='r')ptime=INF;
        else {
            ptime=atoi(argv[2]+1);
            if(ptime==0){
                printf("ptime invalid!\n");
                return -1;
            }
        }
    }
    if((ht=gethostbyname(argv[1]))==NULL){
        printf("hostname invalid!\n");
        return -1;
    }
    memset(&dest,0,sizeof(dest));
    dest.sin_family=AF_INET;
    memcpy(&dest.sin_addr,ht->h_addr_list[0],sizeof(dest.sin_addr));
    if((sock_raw=socket(PF_INET,SOCK_RAW,IPPROTO_ICMP))<0){
        printf("socket error!\n");
        close(sock_raw);
        return -1;
    }
    if(setsockopt(sock_raw,SOL_SOCKET,SO_SNDBUF,&SOCK_DEFAULT_BUFSIZE,sizeof(SOCK_DEFAULT_BUFSIZE))<0){
        printf("setsockopt error!\n");
        close(sock_raw);
        return -1;
    }
    if(setsockopt(sock_raw,SOL_SOCKET,SO_RCVBUF,&SOCK_DEFAULT_BUFSIZE,sizeof(SOCK_DEFAULT_BUFSIZE))<0){
        printf("setsockopt error!\n");
        close(sock_raw);
        return -1;
    }
    return 0;
}
unsigned short calchecksum(unsigned short*buf,int size){
    int i;
    unsigned int sum=0;
    for(i=0;i<size;i++)sum+=buf[i];
    while(sum&0xffff0000){
        sum=(sum>>16)+(sum&0x0000ffff);
    }
    return ~sum;
}
int unpack(int seq){
    memset(recvbuf,0,sizeof(recvbuf));
    if(recvfrom(sock_raw,recvbuf,sizeof(recvbuf),0,NULL,NULL)<0){
        printf("connect shutdown!\n");
        return -2;
    }
    gettimeofday(&rt,NULL);
    IPHEADER*ip=(IPHEADER*)recvbuf;
    ICMPHEADER*icmp=(ICMPHEADER*)(recvbuf+(((ip->ver_hlen)&0x0f)<<2));
    if(calchecksum((unsigned short*)ip,(((ip->ver_hlen)&0x0f)<<2)/2)!=0){
        printf("ipheader checksum error\n");
        return 0;
    }
    if(calchecksum((unsigned short*)icmp,(ntohs(ip->dlen)-(((ip->ver_hlen)&0x0f)<<2))/2)!=0){
        printf("icmpheader checksum error\n");
        return 0;
    }
    if(icmp->id==getuid()&&icmp->seq==seq&&icmp->type==0){
        printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%.1dms\n",ntohs(ip->dlen)
               ,inet_ntoa((in_addr)(dest.sin_addr))
               ,icmp->seq,ip->ttl,(rt.tv_sec-st.tv_sec)*1000+(rt.tv_usec-st.tv_usec)/1000
               );
        return 0;
    }
    return -1;
}
void packet(int seq){
    memset(sendbuf,0,sizeof(sendbuf));
    ICMPHEADER *icmp=(ICMPHEADER*)sendbuf;
    icmp->type=8;
    icmp->code=0;
    icmp->seq=seq;
    icmp->id=getuid();
    gettimeofday(&st,NULL);
    memcpy(sendbuf+sizeof(ICMPHEADER),&st,sizeof(st));
    icmp->checksum=calchecksum((unsigned short*)sendbuf,(sizeof(ICMPHEADER)+sizeof(timeval))/2);
}
void ping(){
    for(pn=1;pn<=ptime;pn++){
        packet(pn);
        if(sendto(sock_raw,sendbuf,sizeof(IPHEADER)+sizeof(ICMPHEADER)+sizeof(timeval),0,(sockaddr*)&dest,sizeof(dest))<0){
            printf("connect shutdown!\n");
            return;
        }
        while(1){
            timeout.tv_sec=2;
            timeout.tv_usec=0;
            fd_set fdset;
            FD_ZERO(&fdset);
            FD_SET(sock_raw,&fdset);
           int res=select(sock_raw+1,&fdset,NULL,NULL,&timeout);
           if(res<0){
                printf("connect shutdown!\n");
               return;
           }else if(res==0){
                printf("0 byte from %s: request timeout!\n",inet_ntoa((in_addr)(dest.sin_addr)));
                break;
           }else if(FD_ISSET(sock_raw,&fdset)){
               int f=unpack(pn);
               if(f==-1){
                    continue;
               }else if(f==-2){
                   return;
               }else {
                   cnt++;
                   break;
               }
           }
        }
    sleep(1);
    }
}
void deal_f(int arg){
    gettimeofday(&end,NULL);
    if(pn==1){
      printf("0 packets transmitted, 0 recieved, NAN lossed, time=%dms\n",(end.tv_sec-start.tv_sec)*1000+(end.tv_usec-start.tv_usec)/1000);
    }
    else printf("%d packets transmitted, %d recieved, %%%.0f lossed, time=%dms\n",pn-1,cnt,(pn-1-cnt)*100.0/(pn-1),(end.tv_sec-start.tv_sec)*1000+(end.tv_usec-start.tv_usec)/1000);
    close(sock_raw);
    exit(0);
}
int main(int argc,char*argv[]){
    gettimeofday(&start,NULL);
    //test
    //argc=2;
    //argv[1]="www.baidu.com";
    //endtest
    if(init(argc,argv)<0)return -1;
    signal(SIGINT,deal_f);
    printf("PING %s (%s) %d bytes of data:\n",ht->h_name,inet_ntoa((in_addr)(dest.sin_addr)),64);
    ping();
    deal_f(0);
    return 0;
}

代码介绍:完成了ping。(存在问题,本地到网络的转换,但是我因为(懒)时间原因,未作修改,不影响大体功能)
知识点:
ip报文头与icmp报文头,需要网络标准。最好是单字节对齐
select(maxfd,fdset,NULL,NULL,timeout)的使用,关键:初始化fdset,初始化timeout。返回值0:超时;返回值-1:error;返回值大于0:有可读信息,如FD_SET()加入多个描述符,使用FD_ISSET()判断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值