• 收发ICMP封包,实现ping


      1 #include "stdafx.h"
      2 
      3 #include <WINSOCK2.H>
      4 #pragma comment(lib, "Ws2_32.lib")
      5 
      6 #define ECHO_REPLY   0  //回应
      7 #define ECHO_REQUEST 8  //请求回应
      8 
      9 struct ip_hdr
     10 {
     11     unsigned char h_len:4;         //length of header
     12     unsigned char version:4;       //Version of IP
     13     unsigned char tos;             //Type of service
     14     unsigned short total_len;      //total length of the packet
     15     
     16     unsigned short ident;          //unique identifier
     17     unsigned short frag_and_flags; //flags
     18     
     19     unsigned char ttl;             //ttl
     20     unsigned char proto;           //protocol(TCP ,UDP etc)
     21     unsigned short checksum;       //IP checksum
     22     
     23     unsigned int sourceIP;
     24     unsigned int destIP;
     25 };
     26 
     27 struct icmp_hdr 
     28 {
     29     BYTE icmp_type;     //类型
     30     BYTE icmp_code;     //代码
     31     USHORT icmp_cksum;  //效验和
     32     USHORT icmp_id;     //n
     33     USHORT icmp_seq;    //n
     34     ULONG  icmp_data;   //GetTickout()
     35 };
     36 
     37 //计算ICMP封包校验和
     38 WORD CalcCheckSum(IN unsigned short* addr,IN int len)
     39 {
     40     int        nleft = len;
     41     int        sum = 0;
     42     unsigned short* w = addr;
     43     unsigned short answer = 0;
     44     
     45     while(nleft > 1) 
     46     {
     47         sum += *w++;
     48         nleft -= 2;
     49     }
     50     
     51     if(nleft == 1) 
     52     {
     53         *(unsigned char*)(&answer) = *(unsigned char*)w;
     54         sum += answer;
     55     }
     56     
     57     sum = (sum >> 16) + (sum & 0xffff); //高16位 + 低16位
     58     sum += (sum >> 16);                 //+进位
     59     answer = ~sum;                      //取反
     60     
     61     return (answer);
     62 }
     63 
     64 int main(int argc, char* argv[])
     65 {
     66     //socket初始化
     67     WSADATA wsaData;
     68     WSAStartup(MAKEWORD(2, 2), &wsaData);
     69 
     70     //没有域名,返回
     71     if (argc < 2)
     72     {
     73         puts("Get Domain Error");
     74         return 0;
     75     }
     76 
     77     //域名转IP地址
     78     HOSTENT *pHost = gethostbyname(argv[1]);
     79     if (pHost == NULL)
     80     {
     81         puts("Get Domain Error");
     82         return 0;
     83     }
     84 
     85     unsigned long nAddress = ((long**)pHost->h_addr_list)[0][0];
     86     sockaddr_in addrSend;
     87     addrSend.sin_family = AF_INET;
     88     addrSend.sin_port = htons(0);
     89     addrSend.sin_addr.s_addr = nAddress;
     90     
     91     //创建原始套接字
     92     SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
     93     if (sRaw == INVALID_SOCKET)
     94     {
     95         puts("socket error");
     96         return 0;
     97     }
     98 
     99     printf("Pinging [ %s ] with 32 bytes of data:
    
    ", argv[1]);
    100 
    101     char szSend[32] = {0};
    102     for (int i = 0; i < 4; i++)
    103     {
    104         icmp_hdr *pICMP = (icmp_hdr *)szSend;
    105         pICMP->icmp_code = 0;
    106         pICMP->icmp_cksum = 0;
    107         pICMP->icmp_data = ::GetTickCount();
    108         pICMP->icmp_id = (unsigned short)GetCurrentProcessId();
    109         pICMP->icmp_seq = i;
    110         pICMP->icmp_type = ECHO_REQUEST;
    111 
    112         pICMP->icmp_cksum = CalcCheckSum((unsigned short *)pICMP, sizeof(icmp_hdr));
    113 
    114         //发送封包
    115         sendto(sRaw, szSend, sizeof(szSend), 0, (sockaddr *)&addrSend, sizeof(addrSend));
    116 
    117         //通过选择模型,设置等待时间
    118         fd_set fd;
    119         FD_ZERO(&fd);
    120         FD_SET(sRaw, &fd);
    121         timeval tv = {1, 0};
    122         int nResult = select(0, &fd, NULL, NULL, &tv);
    123         if (nResult == 0)
    124         {
    125             puts("Time Out");
    126             continue;
    127         }
    128 
    129         //接收封包
    130         char szRecv[MAXBYTE];
    131         sockaddr_in addrRecv;
    132         int nLen = sizeof(addrRecv);
    133         recvfrom(sRaw, szRecv, sizeof(szRecv), 0, (sockaddr *)&addrRecv, &nLen);
    134 
    135         //检验校验和
    136         ip_hdr * pIPRecv = (ip_hdr *)szRecv;
    137         icmp_hdr *pICMPRecv = (icmp_hdr *)(pIPRecv + 1);
    138 
    139         //校验和为0,表示封包正确
    140         if (!CalcCheckSum((unsigned short *)pICMPRecv, sizeof(icmp_hdr)))
    141         {
    142             //计算时间间隔
    143             DWORD dwTime = ::GetTickCount() - pICMPRecv->icmp_data;
    144             
    145             printf("Reply from %s: bytes=%d time=%dms TTL=%d
    ", 
    146                 inet_ntoa(addrRecv.sin_addr), 
    147                 sizeof(szRecv), 
    148                 dwTime, 
    149                 pIPRecv->ttl);
    150         }
    151     }
    152 
    153 
    154     //格式控制
    155     puts("");
    156 
    157     //socket释放资源
    158     WSACleanup( );
    159     return 0;
    160 }
  • 相关阅读:
    初识多线程
    java开发中我们经常用到的一些名词
    gitHub提交代码
    Java-基础-HashMap
    Java-基础-LinkedList
    Java-基础-ArrayList
    Java-基础-JDK动态代理
    Java-基础-反射
    RabbitMQ-延迟队列
    RabbitMQ-TTL-死信队列_DLX
  • 原文地址:https://www.cnblogs.com/luzhiyuan/p/3923092.html
Copyright © 2020-2023  润新知