首页 > 代码库 > vc实现ping

vc实现ping

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//ping.h
#ifndef _CPING_H_
#define _CPING_H_
#include <Winsock2.h>
#include <Windows.h>
#pragma pack(1)
 
#define ICMP_ECHOREPLY  0
#define ICMP_ECHOREQ    8
#define REQ_DATASIZE    32      // Echo 请求数据的大小
 
class CPing
{
public:
    //ping host, nRetries-ping次数
    bool Ping(LPCSTR pstrHost, UINT nRetries = 4);
 
    void Result(int* nElapseTime, float* fMissPack = NULL, u_char* cTTL = NULL);
    //void Result(CPing::REQ_RESULT& result);
 
private:
    int  WaitForEchoReply(SOCKET s);
    //ICMP回应的请求和回答函数
    int     SendEchoRequest(SOCKET, LPSOCKADDR_IN);
    DWORD   RecvEchoReply(SOCKET, LPSOCKADDR_IN, u_char *);
    u_short in_cksum(u_short *addr, int len);
 
private:
    struct REQ_RESULT
    {
        int         nElapseTime;    //请求响应时间。
        u_char      cTTL;           //请求TTL(生存时间)
        float       fMissPack;  //丢包率
    };
 
    REQ_RESULT m_Result;
};
 
// IP Header -- RFC 791
typedef struct tagIPHDR
{
    u_char  VIHL;           // Version and IHL
    u_char  TOS;            // Type Of Service
    short   TotLen;         // Total Length
    short   ID;             // Identification
    short   FlagOff;        // Flags and Fragment Offset
    u_char  TTL;            // Time To Live
    u_char  Protocol;       // Protocol
    u_short Checksum;       // Checksum
    struct  in_addr iaSrc;  // Internet Address - Source
    struct  in_addr iaDst;  // Internet Address - Destination
}IPHDR, *PIPHDR;
 
 
// ICMP Header - RFC 792
typedef struct tagICMPHDR
{
    u_char  Type;           // Type
    u_char  Code;           // Code
    u_short Checksum;       // Checksum
    u_short ID;             // Identification
    u_short Seq;            // Sequence
    char    Data;           // Data
}ICMPHDR, *PICMPHDR;
 
 
 
// ICMP Echo Request
typedef struct tagECHOREQUEST
{
    ICMPHDR icmpHdr;
    DWORD   dwTime;
    char    cData[REQ_DATASIZE];
}ECHOREQUEST, *PECHOREQUEST;
 
 
// ICMP Echo Reply
typedef struct tagECHOREPLY
{
    IPHDR   ipHdr;
    ECHOREQUEST echoRequest;
    char    cFiller[256];
}ECHOREPLY, *PECHOREPLY;
 
#pragma pack()
 
#endif

  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//ping.cpp
#include "ping.h"
 
#pragma comment(lib, "ws2_32.lib")
 
bool CPing::Ping(LPCSTR pstrHost, UINT nRetries)
{
    //创建一个Raw套节字
    SOCKET rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (rawSocket == INVALID_SOCKET)
    {
        int err = WSAGetLastError();
        return false;
    }
    int nNetTimeout = 1000;//1秒
    //发送时限
    setsockopt(rawSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&nNetTimeout,sizeof(int));
    //接收时限
    setsockopt(rawSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout,sizeof(int));
 
    //获得主机信息
    LPHOSTENT lpHost = gethostbyname(pstrHost);
    if (lpHost == NULL)
    {
        return false;
    }
     
    //构造目标套节字地址信息
    struct    sockaddr_in saDest;
    struct    sockaddr_in saSrc;
    saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
    saDest.sin_family = AF_INET;
    saDest.sin_port = 3077;//0;
 
    DWORD    dwTimeSent;
    u_char   cTTL;
    int     nRet;
    int     nRecvNum = 0;
    int     nTotalTime = 0;
 
    //多次ping
    for (UINT nLoop = 0; nLoop < nRetries; ++nLoop)
    {
        //发送ICMP回应请求
        if ((nRet = SendEchoRequest(rawSocket, &saDest)) < 0)
        {
            break;
        }
 
        if ((nRet = WaitForEchoReply(rawSocket)) == SOCKET_ERROR)
        {
            break;
        }
        if (nRet)
        {
            //获得回应
            if ( (dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL)) < 0)
            {
                nRet = dwTimeSent;
                break;
            }
            //计算时间
            nTotalTime += GetTickCount() - dwTimeSent;
            //Sleep(1000);
            ++nRecvNum;
        }
    }
    closesocket(rawSocket);
    if (nRecvNum > 0 && nRet >= 0)
    {
        m_Result.nElapseTime = nTotalTime/nRetries;
        m_Result.cTTL = cTTL;
        m_Result.fMissPack = (float)(nRetries - nRecvNum)/nRetries;
        return true;
    }
 
    return false;
}
 
//发送ICMPECHO数据包请求
int CPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
{
    static ECHOREQUEST echoReq;
    static int nId = 1;
    static int nSeq = 1;
    int nRet;
 
    //构造回应请求
    echoReq.icmpHdr.Type        = ICMP_ECHOREQ;
    echoReq.icmpHdr.Code        = 0;
    echoReq.icmpHdr.Checksum    = 0;
    echoReq.icmpHdr.ID          = nId++;
    echoReq.icmpHdr.Seq         = nSeq++;
 
    for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
        echoReq.cData[nRet] = ‘ ‘+nRet;
 
    //保存发送时间
    echoReq.dwTime  = GetTickCount();
 
    echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));
 
    //发送请求
    nRet = sendto(s,                       
                 (LPSTR)&echoReq,          
                 sizeof(ECHOREQUEST),
                 0,                        
                 (LPSOCKADDR)lpstToAddr,
                 sizeof(SOCKADDR_IN));  
    //检查返回值
    if (nRet == SOCKET_ERROR)
    {
    }
 
    return (nRet);
}
 
//接收ICMPECHO数据包回应
DWORD CPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
{
    ECHOREPLY echoReply;
    int nRet;
    int nAddrLen = sizeof(struct sockaddr_in);
 
    //接收请求回应
    nRet = recvfrom(s,                 
                    (LPSTR)&echoReply, 
                    sizeof(ECHOREPLY), 
                    0,                 
                    (LPSOCKADDR)lpsaFrom,
                    &nAddrLen);        
 
    //检查返回值
    if (nRet == SOCKET_ERROR)
    {
        return nRet;
    }
 
    //返回发送的时间
    *pTTL = echoReply.ipHdr.TTL;
 
    return(echoReply.echoRequest.dwTime);          
}
 
//等待回应
int CPing::WaitForEchoReply(SOCKET s)
{
    struct timeval Timeout;
    fd_set readfds;
 
    readfds.fd_count = 1;
    readfds.fd_array[0] = s;
    Timeout.tv_sec = 1;
    Timeout.tv_usec = 0;
 
    return(select(1, &readfds, NULL, NULL, &Timeout));
}
 
//转换地址
u_short CPing::in_cksum(u_short *addr, int len)
{
    register int nleft = len;
    register u_short *w = addr;
    register u_short answer;
    register int sum = 0;
 
    while( nleft > 1 )  {
        sum += *w++;
        nleft -= 2;
    }
 
    if( nleft == 1 ) {
        u_short u = 0;
 
        *(u_char *)(&u) = *(u_char *)w ;
        sum += u;
    }
 
    sum = (sum >> 16) + (sum & 0xffff);  
    sum += (sum >> 16);          
    answer = ~sum;             
    return (answer);
}
 
void CPing::Result(int* nElapseTime, float* fMissPack, u_char* cTTL)
{
    if (nElapseTime)
    {
        *nElapseTime = m_Result.nElapseTime;
    }
    if (fMissPack)
    {
        *fMissPack = m_Result.fMissPack;
    }
    if (cTTL)
    {
        *cTTL = m_Result.cTTL;
    }
}

  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//main.cpp
#include <stdlib.h>
#include <iostream>
#include <string>
#include "ping.h"
 
int main(int argn, char *argv[])
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
 
    wVersionRequested = MAKEWORD( 1, 1 );
 
    err = WSAStartup( wVersionRequested, &wsaData );
 
    CPing ping;
    bool bResult = false;
    if (argn == 2)
    {
        bResult = ping.Ping(argv[1]);
    }
    else
    {
        bResult = ping.Ping("www.baidu.com");
    }
     
    std::cout << "result : " << bResult << std::endl;
    if (bResult)
    {
        int nTime;
        u_char nTTL;
        float fMiss;
        ping.Result(&nTime, &fMiss, &nTTL);
 
        std::cout << "time : " << nTime << " TTL : " << (int)nTTL << " miss : " << fMiss*100 << "% " << std::endl;
    }
    return 0;
}