微軟ping程序源代碼完整版(上)

字號:

編寫自己的一個(gè)ping程序,可以說是許多人邁出網(wǎng)絡(luò)編程的第一步吧!!這個(gè)ping程序的源代碼經(jīng)過我的修改和調(diào)試,基本上可以取代windows中自帶的ping程序. 各個(gè)模塊后都有我的詳細(xì)注釋和修改日志,希望能夠?qū)Υ蠹业膶W(xué)習(xí)有所幫助!!
    /* 本程序的主要源代碼來自MSDN網(wǎng)站, 筆者只是做了一些改進(jìn)和注釋! 另外需要注意的是在Build之前,必須加入ws2_32.lib庫文件,否則會提示"error LNK2001:"的錯(cuò)誤!*/
    /**************************************************************************\
    | Version 1.1 修改記錄: |
    | <1> 解決了socket阻塞的問題,從而能夠正確地處理超時(shí)的請求! |
    |--------------------------------------------------------------------|
    | Version 1.2 修改記錄: |
    | <1> 增加了由用戶控制發(fā)送ICMP包的數(shù)目的功能(即命令的第二個(gè)參數(shù)). |
    | <2> 增加了對ping結(jié)果的統(tǒng)計(jì)功能. |
    \***************************************************************************/
    #pragma pack(4)
    #i nclude
    #i nclude
    #i nclude
    #define ICMP_ECHO 8
    #define ICMP_ECHOREPLY 0
    #define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
    /* The IP header */
    typedef struct iphdr {
    unsigned int h_len:4; // length of the header
    unsigned int 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 icmphdr {
    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 DEF_PACKET_NUMBER 4 /* 發(fā)送數(shù)據(jù)報(bào)的個(gè)數(shù) */
    #define MAX_PACKET 1024
    #define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
    #define xfree(p) HeapFree (GetProcessHeap(),0,(p))
    void fill_icmp_data(char *, int);
    USHORT checksum(USHORT *, int);
    int decode_resp(char *,int ,struct sockaddr_in *);
    void Usage(char *progname){
    fprintf(stderr,"Usage:\n");
    fprintf(stderr,"%s [number of packets] [data_size]\n",progname);
    fprintf(stderr,"datasize can be up to 1Kb\n");
    ExitProcess(STATUS_FAILED);
    }
    int main(int argc, char **argv){
    WSADATA wsaData;
    SOCKET sockRaw;
    struct sockaddr_in dest,from;
    struct hostent * hp;
    int bread,datasize,times;
    int fromlen = sizeof(from);
    int timeout = 1000;
    int statistic = 0; /* 用于統(tǒng)計(jì)結(jié)果 */
    char *dest_ip;
    char *icmp_data;
    char *recvbuf;
    unsigned int addr=0;
    USHORT seq_no = 0;
    if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){
    fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
    ExitProcess(STATUS_FAILED);
    }
    if (argc <2 ) {
    Usage(argv[0]);
    }
    sockRaw = WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL, 0,WSA_FLAG_OVERLAPPED);
    //
    //注:為了使用發(fā)送接收超時(shí)設(shè)置(即設(shè)置SO_RCVTIMEO, SO_SNDTIMEO),
    // 必須將標(biāo)志位設(shè)為WSA_FLAG_OVERLAPPED !
    //
    if (sockRaw == INVALID_SOCKET) {
    fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
    ExitProcess(STATUS_FAILED);
    }
    bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,
    sizeof(timeout));
    if(bread == SOCKET_ERROR) {
    fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
    ExitProcess(STATUS_FAILED);
    }
    timeout = 1000;
    bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
    sizeof(timeout));
    if(bread == SOCKET_ERROR) {
    fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
    ExitProcess(STATUS_FAILED);
    }
    memset(&dest,0,sizeof(dest));
    hp = gethostbyname(argv[1]);
    if (!hp){
    addr = inet_addr(argv[1]);
    }
    if ((!hp) && (addr == INADDR_NONE) ) {
    fprintf(stderr,"Unable to resolve %s\n",argv[1]);
    ExitProcess(STATUS_FAILED);
    }
    if (hp != NULL)
    memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
    else
    dest.sin_addr.s_addr = addr;
    if (hp)
    dest.sin_family = hp->h_addrtype;
    else
    dest.sin_family = AF_INET;
    dest_ip = inet_ntoa(dest.sin_addr);
    //
    // atoi函數(shù)原型是: int atoi( const char *string );
    // The return value is 0 if the input cannot be converted to an integer !
    //
    if(argc>2)
    {
    times=atoi(argv[2]);
    if(times == 0)
    times=DEF_PACKET_NUMBER;
    }
    else
    times=DEF_PACKET_NUMBER;