Windows系统ping命令的c++实现

// ping.cpp : 定义控制台应用程序的入口点。
//

#include <winsock2.h> 
#include <stdio.h> 
#include <stdlib.h> 

#define ICMP_ECHO 8 
#define ICMP_ECHOREPLY 0 

/* The IP header */ 
typedef struct iphdr 
{ 
    unsigned char h_len:4; // length of the header 
    unsigned char version:4; // Version of IP 
    unsigned char tos; // Type of service 
    unsigned short total_len; // total length of the packet 
    unsigned short ident; // unique identifier 
    unsigned short frag_and_flags; // flags 
    unsigned char ttl; 
    unsigned char proto; // protocol (TCP, UDP etc) 
    unsigned short checksum; // IP checksum 
    unsigned int sourceIP; 
    unsigned int destIP; 
}IpHeader; 

/* ICMP header */
typedef struct _ihdr 
{ 
    BYTE i_type; 
    BYTE i_code; /* type sub code */
    USHORT i_cksum; 
    USHORT i_id; 
    USHORT i_seq; /* This is not the std header, but we reserve space for time */ 
    ULONG timestamp; 
}IcmpHeader; 

#define STATUS_FAILED 0xFFFF 
#define DEF_PACKET_SIZE 32 
#define MAX_PACKET 1024 

/* The response is an IP packet. We must decode the IP header to locate the ICMP data */ 
void decode_resp(char *buf, int bytes,struct sockaddr_in *from)
{
    IpHeader *iphdr; 
    IcmpHeader *icmphdr; 
    unsigned short iphdrlen; 

    iphdr=(IpHeader*)buf; 
    iphdrlen=sizeof(IpHeader)+sizeof(IcmpHeader);

    if(bytes<iphdrlen) 
    { 
        printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr)); 
    } 

    icmphdr=(IcmpHeader*)(buf+sizeof(IpHeader)); 
    if(icmphdr->i_type!=ICMP_ECHOREPLY) 
    { 
        fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type); return; 
    }

    if(icmphdr->i_id!=(USHORT)GetCurrentProcessId()) 
    { 
        fprintf(stderr,"someone else's packet!\n"); return ; 
    }

    int correct=0;
    for(int k=0;k<bytes-iphdrlen;k++)
    {
        if(*(buf+iphdrlen+k)=='E')
        {
            correct++;
        }
    }

    printf("来自 %s 的回复: 字节=%d 时间=%dms TTL=%d\n",\
    inet_ntoa(from->sin_addr),correct,GetTickCount()-icmphdr->timestamp,iphdr->ttl); 
} 

USHORT checksum(USHORT *buffer, int size) 
{ 
    unsigned long cksum=0; 

    while(size>1) 
    { 
        cksum+=*buffer++; 
        size-=sizeof(USHORT); 
    } 

    if(size) 
    { 
        cksum+=*(UCHAR*)buffer; 
    } 

    cksum=(cksum>>16)+(cksum&0xffff); 
    cksum+=(cksum>>16); 

    return (USHORT)(~cksum); 
} 

/* Helper function to fill in various stuff in our ICMP request. */ 
void fill_icmp_data(char *icmp_data, int datasize)
{ 
    char *datapart=NULL; 
    IcmpHeader *icmp_hdr=NULL; 
    icmp_hdr=(IcmpHeader*)icmp_data; 
    icmp_hdr->i_type=ICMP_ECHO; 
    icmp_hdr->i_code=0; 
    icmp_hdr->i_id=(USHORT)GetCurrentProcessId(); 
    icmp_hdr->i_cksum=0; 
    icmp_hdr->i_seq++; 
    icmp_hdr->timestamp=GetTickCount(); 
    datapart=icmp_data+sizeof(IcmpHeader); // Place some junk in the buffer. 
    memset(datapart,'E',datasize-sizeof(IcmpHeader)); 
    icmp_hdr->i_cksum=checksum((USHORT*)icmp_data,datasize);
} 

int main(int argc, char *argv[])
{ 
    int count=1;
    int error=-1;
    int datasize=0; 
    int timeout=3000; 
    struct sockaddr_in addrServer; 
    struct hostent *phostent=NULL; 
    int destlen=sizeof(addrServer); 
    char *dest_ip=NULL; 
    char icmp_data[MAX_PACKET]; 
    char recvbuf[MAX_PACKET]; 
    unsigned int addr=0; 
    char srcIP[MAX_PATH]="0.0.0.0";
    char dstIP[MAX_PATH]="127.0.0.1";

    for(int n=1;n<argc;)
    {
        if(!strcmp(argv[n],"-S"))
        {            
            n++;strcpy_s(srcIP,argv[n++]);
        }
        else if(!strcmp(argv[n],"-n"))
        {
            n++;count=atoi(argv[n++]);
        }
        else
        {
            strcpy_s(dstIP,argv[n++]);
        }
    }

    WSADATA wsaData={0}; 
    if(WSAStartup(MAKEWORD(1,1),&wsaData)!=0)
    { 
        printf("WSA startup error\n"); 
        ExitProcess(STATUS_FAILED); 
    } 

    SOCKET sockClient=WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,0); 
    if(sockClient==INVALID_SOCKET) 
    { 
        printf("WSA socket error\n"); 
        ExitProcess(STATUS_FAILED); 
    } 

    sockaddr_in addrClient;
    addrClient.sin_addr.S_un.S_addr=inet_addr(srcIP);

    addrClient.sin_family=AF_INET;
    addrClient.sin_port=htons(0);

    error=bind(sockClient,(SOCKADDR *)&addrClient,sizeof(addrClient));
    if(error)
    {
        closesocket(sockClient);
        printf("bind client error\n");
        return WSACleanup();
    }

    unsigned long ul=true;
    error=ioctlsocket(sockClient,FIONBIO,(unsigned long*)&ul);
    if(error)
    {
        closesocket(sockClient);
        printf("set ioctlsocket error\n");
        return WSACleanup();
    }

    error=setsockopt(sockClient,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, sizeof(timeout)); 
    if(error==SOCKET_ERROR) 
    { 
        fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); 
        ExitProcess(STATUS_FAILED); 
    } 

    error=setsockopt(sockClient,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, sizeof(timeout)); 
    if(error==SOCKET_ERROR) 
    { 
        fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError()); 
        ExitProcess(STATUS_FAILED); 
    } 

    memset(&addrServer,0,sizeof(addrServer)); 
    phostent=gethostbyname(dstIP); 
    if(!phostent)
    { 
        addr=inet_addr(dstIP); 
    } 

    if((!phostent)&&(addr==INADDR_NONE)) 
    { 
        fprintf(stderr,"Unable to resolve host %s\n",dstIP); 
        ExitProcess(STATUS_FAILED); 
    } 

    if(phostent!=NULL) 
    {
        memcpy(&(addrServer.sin_addr),phostent->h_addr,phostent->h_length);
    }
    else
    {
        addrServer.sin_addr.s_addr=addr; 
    }

    if(phostent) 
    {
        addrServer.sin_family=phostent->h_addrtype;
    }
    else
    {
        addrServer.sin_family=AF_INET; 
        dest_ip=inet_ntoa(addrServer.sin_addr);
    } 

    datasize=DEF_PACKET_SIZE; 
    datasize+=sizeof(IcmpHeader); 
    memset(icmp_data,0,MAX_PACKET);

    for(int i=0;i<count;i++) 
    {         
        fill_icmp_data(icmp_data,datasize); 
        int num=sendto(sockClient,icmp_data,datasize,0,(struct sockaddr*)&addrServer, sizeof(addrServer)); 
        if(num==SOCKET_ERROR)
        { 
            error=WSAGetLastError();
            if(error==WSAETIMEDOUT) 
            { 
                fprintf(stderr,"errorcode=%d\n",error); 
                continue; 
            }
        } 
        if(num<datasize) 
        { 
            fprintf(stdout,"Write %d bytes\n",num); 
        }

        timeval tm;
        int len=sizeof(int);
        fd_set set;

        for(int k=0;k<3;k++)
        {
            num=recvfrom(sockClient,recvbuf,MAX_PACKET,0,(struct sockaddr*)&addrServer, &destlen); 
            if(num!=SOCKET_ERROR)
            {
                break;
            }

            if(num==SOCKET_ERROR)
            {    
                Sleep(1);
                tm.tv_sec=0;        
                tm.tv_usec=1;        
                FD_ZERO(&set);        
                FD_SET(sockClient,&set);        
                if(select(sockClient,NULL,&set,NULL,&tm)>0)        
                {            
                    getsockopt(sockClient,SOL_SOCKET,SO_ERROR,(char*)&error,&len);            
                }                
            }
        }

        if(num!=SOCKET_ERROR)
        {
            decode_resp(recvbuf,num,&addrServer); 
        }
        else
        {
            printf("Can not find host %s\n",dstIP); 
        }
        if(i>0)
        {
            Sleep(1000);
        }
    } 

    closesocket(sockClient);
    WSACleanup();

    return 0; 
}

编译命令如下:

g++ -std=c++2a -o ping.exe ping.cpp -lws2_32

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

princewwj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值