VC模拟ping发送ICMP数据包

 张越的那本《Visual c++网络程序设计实例详解》很好,他的代码写得很漂亮!

 

      网络编程方面的书籍,那是遗弃许久。这一段时间再次拾起,以补不足!

 

      这是他第一章的实例,模拟ping来发送ICMP数据包:

 

1、程序源码

[cpp]  view plain copy print ?
  1. //////////////////////////////////////////////////  
  2. // comm.h文件  
  3.   
  4. // 包含一些公共函数  
  5.   
  6. #ifndef __COMM_H__  
  7. #define __COMM_H__  
  8.   
  9. // 校验和的计算  
  10. // 以16位的字为单位将缓冲区的内容相加,如果缓冲区长度为奇数,  
  11. // 则再加上一个字节。它们的和存入一个32位的双字中  
  12. USHORT  checksum(USHORT* buff, int size);  
  13.   
  14. BOOL    SetTTL(SOCKET s, int nValue);  
  15. BOOL    SetTimeout(SOCKET s, int nTime, BOOL bRecv = TRUE);  
  16.   
  17. #endif // __COMM_H__  

 

[cpp]  view plain copy print ?
  1. //////////////////////////////////////////////////  
  2. // protoinfo.h文件  
  3.   
  4. /* 
  5.  
  6. 定义协议格式 
  7. 定义协议中使用的宏 
  8.  
  9.  */  
  10.   
  11. #ifndef __PROTOINFO_H__  
  12. #define __PROTOINFO_H__  
  13.   
  14. #define ETHERTYPE_IP    0x0800  
  15. #define ETHERTYPE_ARP   0x0806  
  16.   
  17. typedef struct _ETHeader         // 14字节的以太头  
  18. {  
  19.     UCHAR   dhost[6];           // 目的MAC地址destination mac address  
  20.     UCHAR   shost[6];           // 源MAC地址source mac address  
  21.     USHORT  type;               // 下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等  
  22. } ETHeader, *PETHeader;  
  23.   
  24. #define ARPHRD_ETHER    1  
  25.   
  26. // ARP协议opcodes  
  27. #define ARPOP_REQUEST   1       // ARP 请求     
  28. #define ARPOP_REPLY     2       // ARP 响应  
  29.   
  30. typedef struct _ARPHeader       // 28字节的ARP头  
  31. {  
  32.     USHORT  hrd;                //  硬件地址空间,以太网中为ARPHRD_ETHER  
  33.     USHORT  eth_type;           //  以太网类型,ETHERTYPE_IP ??  
  34.     UCHAR   maclen;             //  MAC地址的长度,为6  
  35.     UCHAR   iplen;              //  IP地址的长度,为4  
  36.     USHORT  opcode;             //  操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应  
  37.     UCHAR   smac[6];            //  源MAC地址  
  38.     UCHAR   saddr[4];           //  源IP地址  
  39.     UCHAR   dmac[6];            //  目的MAC地址  
  40.     UCHAR   daddr[4];           //  目的IP地址  
  41. } ARPHeader, *PARPHeader;  
  42.   
  43. // 协议  
  44. #define PROTO_ICMP    1  
  45. #define PROTO_IGMP    2  
  46. #define PROTO_TCP     6  
  47. #define PROTO_UDP     17  
  48.   
  49. typedef struct _IPHeader        // 20字节的IP头  
  50. {  
  51.     UCHAR     iphVerLen;      // 版本号和头长度(各占4位)  
  52.     UCHAR     ipTOS;          // 服务类型   
  53.     USHORT    ipLength;       // 封包总长度,即整个IP报的长度  
  54.     USHORT    ipID;           // 封包标识,惟一标识发送的每一个数据报  
  55.     USHORT    ipFlags;        // 标志  
  56.     UCHAR     ipTTL;          // 生存时间,就是TTL  
  57.     UCHAR     ipProtocol;     // 协议,可能是TCP、UDP、ICMP等  
  58.     USHORT    ipChecksum;     // 校验和  
  59.     ULONG     ipSource;       // 源IP地址  
  60.     ULONG     ipDestination;  // 目标IP地址  
  61. } IPHeader, *PIPHeader;   
  62.   
  63. // 定义TCP标志  
  64. #define   TCP_FIN   0x01  
  65. #define   TCP_SYN   0x02  
  66. #define   TCP_RST   0x04  
  67. #define   TCP_PSH   0x08  
  68. #define   TCP_ACK   0x10  
  69. #define   TCP_URG   0x20  
  70. #define   TCP_ACE   0x40  
  71. #define   TCP_CWR   0x80  
  72.   
  73. typedef struct _TCPHeader       // 20字节的TCP头  
  74. {  
  75.     USHORT  sourcePort;         // 16位源端口号  
  76.     USHORT  destinationPort;    // 16位目的端口号  
  77.     ULONG   sequenceNumber;     // 32位序列号  
  78.     ULONG   acknowledgeNumber;  // 32位确认号  
  79.     UCHAR   dataoffset;         // 高4位表示数据偏移  
  80.     UCHAR   flags;              // 6位标志位  
  81.                                 //FIN - 0x01  
  82.                                 //SYN - 0x02  
  83.                                 //RST - 0x04   
  84.                                 //PUSH- 0x08  
  85.                                 //ACK- 0x10  
  86.                                 //URG- 0x20  
  87.                                 //ACE- 0x40  
  88.                                 //CWR- 0x80  
  89.   
  90.     USHORT  windows;            // 16位窗口大小  
  91.     USHORT  checksum;           // 16位校验和  
  92.     USHORT  urgentPointer;      // 16位紧急数据偏移量   
  93. } TCPHeader, *PTCPHeader;  
  94.   
  95. typedef struct _UDPHeader  
  96. {  
  97.     USHORT          sourcePort;     // 源端口号       
  98.     USHORT          destinationPort;// 目的端口号          
  99.     USHORT          len;            // 封包长度  
  100.     USHORT          checksum;       // 校验和  
  101. } UDPHeader, *PUDPHeader;  
  102.   
  103. #endif // __PROTOINFO_H__  

 

 

[cpp]  view plain copy print ?
  1. //////////////////////////////////////////////////  
  2. // comm.cpp文件  
  3.   
  4. #include <winsock2.h>  
  5. #include <windows.h>  
  6. #include "Ws2tcpip.h"  
  7.   
  8. #include "comm.h"  
  9.   
  10. USHORT checksum(USHORT* buff, int size)  
  11. {  
  12.     unsigned long cksum = 0;  
  13.     while(size>1)  
  14.     {  
  15.         cksum += *buff++;  
  16.         size -= sizeof(USHORT);  
  17.     }  
  18.     // 是奇数  
  19.     if(size)  
  20.     {  
  21.         cksum += *(UCHAR*)buff;  
  22.     }  
  23.     // 将32位的chsum高16位和低16位相加,然后取反  
  24.     cksum = (cksum >> 16) + (cksum & 0xffff);  
  25.     cksum += (cksum >> 16);             
  26.     return (USHORT)(~cksum);  
  27. }  
  28.   
  29. BOOL SetTTL(SOCKET s, int nValue)  
  30. {  
  31.     int ret = ::setsockopt(s, IPPROTO_IP, IP_TTL, (char*)&nValue, sizeof(nValue));  
  32.     return ret != SOCKET_ERROR;  
  33. }  
  34.   
  35. BOOL SetTimeout(SOCKET s, int nTime, BOOL bRecv)  
  36. {  
  37.     int ret = ::setsockopt(s, SOL_SOCKET,   
  38.         bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));  
  39.     return ret != SOCKET_ERROR;  
  40. }  

 

[cpp]  view plain copy print ?
  1. ///////////////////////////////////////////  
  2. // ping.cpp文件  
  3.   
  4. #include "../common/initsock.h"  
  5. #include "../common/protoinfo.h"  
  6. #include "../common/comm.h"  
  7.   
  8. #include <stdio.h>  
  9.   
  10. CInitSock theSock;  
  11.   
  12. typedef struct icmp_hdr  
  13. {  
  14.     unsigned char   icmp_type;      // 消息类型  
  15.     unsigned char   icmp_code;      // 代码  
  16.     unsigned short  icmp_checksum;  // 校验和  
  17.   
  18.     // 下面是回显头  
  19.     unsigned short  icmp_id;        // 用来惟一标识此请求的ID号,通常设置为进程ID  
  20.     unsigned short  icmp_sequence;  // 序列号  
  21.     unsigned long   icmp_timestamp; // 时间戳  
  22. } ICMP_HDR, *PICMP_HDR;  
  23.   
  24. int main()  
  25. {  
  26.     // 目的IP地址,即要Ping的IP地址  
  27.     char szDestIp[] = "119.147.15.13";  // 127.0.0.1  
  28.   
  29.     // 创建原始套节字  
  30.     SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);  
  31.   
  32.     // 设置接收超时  
  33.     SetTimeout(sRaw, 1000, TRUE);  
  34.   
  35.     // 设置目的地址  
  36.     SOCKADDR_IN dest;  
  37.     dest.sin_family = AF_INET;  
  38.     dest.sin_port = htons(0);  
  39.     dest.sin_addr.S_un.S_addr = inet_addr(szDestIp);  
  40.   
  41.     // 创建ICMP封包  
  42.     char buff[sizeof(ICMP_HDR) + 32];  
  43.     ICMP_HDR* pIcmp = (ICMP_HDR*)buff;  
  44.   
  45.     // 填写ICMP封包数据,请求一个ICMP回显  
  46.     pIcmp->icmp_type = 8;      
  47.     pIcmp->icmp_code = 0;  
  48.     pIcmp->icmp_id = (USHORT)::GetCurrentProcessId();  
  49.     pIcmp->icmp_checksum = 0;  
  50.     pIcmp->icmp_sequence = 0;  
  51.   
  52.     // 填充数据部分,可以为任意  
  53.     memset(&buff[sizeof(ICMP_HDR)], 'E', 32);  
  54.       
  55.     // 开始发送和接收ICMP封包  
  56.     USHORT  nSeq = 0;  
  57.     char recvBuf[1024];  
  58.     SOCKADDR_IN from;  
  59.     int nLen = sizeof(from);  
  60.     while(TRUE)  
  61.     {  
  62.         static int nCount = 0;  
  63.         int nRet;  
  64.   
  65.         // ping次数  
  66.         if(nCount++ == 1000)  
  67.             break;  
  68.   
  69.         pIcmp->icmp_checksum = 0;  
  70.         pIcmp->icmp_timestamp = ::GetTickCount();  
  71.         pIcmp->icmp_sequence = nSeq++;  
  72.         pIcmp->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) + 32);  
  73.         nRet = ::sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (SOCKADDR *)&dest, sizeof(dest));  
  74.         if(nRet == SOCKET_ERROR)  
  75.         {  
  76.             printf(" sendto() failed: %d /n", ::WSAGetLastError());  
  77.             return -1;  
  78.         }  
  79.         nRet = ::recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);  
  80.         if(nRet == SOCKET_ERROR)  
  81.         {  
  82.             if(::WSAGetLastError() == WSAETIMEDOUT)  
  83.             {  
  84.                 printf(" timed out/n");  
  85.                 continue;  
  86.             }  
  87.             printf(" recvfrom() failed: %d/n", ::WSAGetLastError());  
  88.             return -1;  
  89.         }  
  90.   
  91.         // 下面开始解析接收到的ICMP封包  
  92.         int nTick = ::GetTickCount();  
  93.         if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR))  
  94.         {  
  95.             printf(" Too few bytes from %s /n", ::inet_ntoa(from.sin_addr));  
  96.         }  
  97.   
  98.         // 接收到的数据中包含IP头,IP头大小为20个字节,所以加20得到ICMP头  
  99.         // (ICMP_HDR*)(recvBuf + sizeof(IPHeader));  
  100.         ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20);   
  101.         if(pRecvIcmp->icmp_type != 0)    // 回显  
  102.         {  
  103.             printf(" nonecho type %d recvd /n", pRecvIcmp->icmp_type);  
  104.             return -1;  
  105.         }  
  106.   
  107.         if(pRecvIcmp->icmp_id != ::GetCurrentProcessId())  
  108.         {  
  109.             printf(" someone else's packet! /n");  
  110.             return -1;  
  111.         }  
  112.           
  113.         printf("从 %s 返回 %d 字节:", inet_ntoa(from.sin_addr),nRet);  
  114.         printf(" 数据包序列号 = %d. /t", pRecvIcmp->icmp_sequence);  
  115.         printf(" 延时大小: %d ms", nTick - pRecvIcmp->icmp_timestamp);  
  116.         printf(" /n");  
  117.   
  118.         // 每一秒发送一次就行了  
  119.         ::Sleep(1000);  
  120.     }  
  121.     return 0;  
  122. }  

 

2、打开OmniPeek,运行程序并抓包分析截图如下:

VC模拟ping发送ICMP数据包_第1张图片

 

你可能感兴趣的:(VC模拟ping发送ICMP数据包)