简单的实现了一个ping程序,没有做icmp差错报文的检查。

支持自定义字节数,支持发包个数 

 

  1 #pragma pack(4)
  2 
  3 #define  ECHO_REQUEST        8
  4 #define  DATASIZE            65500
  5 #define  PACKETSIZE          65535
  6 
  7 struct iphdr
  8 {
  9     unsigned char  ip_hdr_len : 4; //包头长度
 10     unsigned char  ip_version : 4; //版本
 11     unsigned char  ip_tos;
 12 
 13     unsigned short ip_length;  //总长度
 14     unsigned short ip_identify;//标识
 15     unsigned short ip_offset;//片偏移
 16     unsigned char  ip_ttl;
 17     unsigned char  ip_protocol;
 18     unsigned short ip_cksum;
 19 
 20     struct in_addr ip_src; //源地址
 21     struct in_addr ip_dst; //目的地址
 22 };
 23 
 24 struct icmphdr
 25 {
 26     unsigned char  icmp_type; //8位类型
 27     unsigned char  icmp_code; //8位代码
 28     unsigned short icmp_cksum; //16位的校验和
 29 
 30     unsigned short icmp_identify;
 31     unsigned short icmp_seq;
 32     
 33     LONGLONG       icmp_timestamp;
 34     char           icmp_data[DATASIZE];
 35 };
 36 
 37 unsigned short checksum(int count,unsigned short* addr)
 38 {
 39     long sum = 0;
 40 
 41     while(count > 1)
 42     {
 43         sum   +=*addr++;
 44         count -= sizeof(unsigned short);
 45     }
 46 
 47     if(count > 0)
 48     {
 49         sum  +=*(unsigned char*)addr;
 50     }
 51 
 52     while(sum >> 16)
 53     {
 54         sum = (sum & 0xFFFF) + (sum >> 16);
 55     }
 56     
 57     return (unsigned short)(~sum);
 58 }
 59 
 60 void packet_pad(char * buf,int payload)
 61 {
 62     char pad[] = "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x7\x73\x74\x75\x76\x77";
 63     
 64     int size   = sizeof(pad) -1;
 65     int count  = payload / size;
 66     int remain = payload % size;
 67     int offset = 0; //偏移
 68 
 69     memset((void *)buf,0,payload);
 70 
 71     for(int i = 0;i < count; ++i)
 72     {
 73         memcpy((void *)(buf + offset),(void *)pad,size);
 74         offset += size;
 75     }
 76 
 77     memcpy((void *)(buf + offset),(void *)pad,remain);
 78 }
 79 
 80 LONGLONG getsystickcount64()
 81 {
 82     static LARGE_INTEGER tickspersecond = {0};
 83     LARGE_INTEGER tick;
 84 
 85     if(!tickspersecond.QuadPart)
 86     {
 87         QueryPerformanceFrequency(&tickspersecond);
 88     }
 89 
 90     QueryPerformanceCounter(&tick);
 91 
 92     LONGLONG seconds     = tick.QuadPart / tickspersecond.QuadPart;
 93     LONGLONG leftPart    = tick.QuadPart - (tickspersecond.QuadPart * seconds);
 94     LONGLONG millseconds = ((leftpart << 10)  - ((leftpart << 4) + (leftpart << 3)))  / tickspersecond.QuadPart;
 95     LONGLONG ret         = ((seconds  << 10)  - ((seconds  << 4) + (seconds  << 3)))  + millseconds;
 96 
 97     return ret;
 98 };
 99 
100 bool ping(char * target,int payload,int count)
101 {
102     WSADATA wsaData;
103     WSAStartup(MAKEWORD(2, 2), &wsaData);
104 
105     SOCKET soc = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
106     if(soc == -1)
107     {
108         printf("create raw socket failed!\n");
109         return false;
110     }
111     
112     if(payload > DATASIZE)
113     {
114         printf("发送的字节数有错误,有效范围从 0 到 %d",DATASIZE);
115         return false;
116     }
117 
118     payload = payload - sizeof(LONGLONG); 
119 
120     struct sockaddr_in  addrsrv;
121 
122     addrsrv.sin_family        = AF_INET;
123     addrsrv.sin_port          = htons(0);
124     struct hostent* phostent  = gethostbyname(target);  
125     if (phostent)  
126     {  
127         addrsrv.sin_addr.s_addr = *(u_long *)phostent->h_addr_list[0];
128     }
129 
130     printf("正在 Ping %s [%s] 具有 %d 字节的数据: \n",target,inet_ntoa(addrsrv.sin_addr),payload + sizeof(LONGLONG));
131     
132     icmphdr ihdr       = {0};
133     
134     memset((void *)ihdr.icmp_data,0,DATASIZE);
135     packet_pad(ihdr.icmp_data,payload); //填充数据
136     
137     ihdr.icmp_type        = ECHO_REQUEST;
138     ihdr.icmp_identify    = (unsigned short)GetCurrentProcessId();
139     
140     int hdr_len           = payload + sizeof(icmphdr) - DATASIZE;
141 
142     struct timeval timeout; 
143     struct sockaddr_in addrcli;
144 
145     char recv[PACKETSIZE]   = {0};
146 
147     unsigned long interval  = 0;
148     unsigned long avgdelay  = 0;
149     unsigned long maxdelay  = 0;
150     unsigned long mindelay  = ~0;
151 
152     unsigned int  sndcnt = count;
153     unsigned int  loscnt = 0;
154 
155     for(int seq = 0; seq < count; ++seq)
156     {
157         memset((void *)recv,0,PACKETSIZE);
158 
159         ihdr.icmp_seq        = seq;
160         ihdr.icmp_cksum      = 0;
161         ihdr.icmp_timestamp  = getsystickcount64(); //时间戳
162         ihdr.icmp_cksum      = checksum(hdr_len,(unsigned short *)&ihdr);
163         
164         if(sendto(soc,(char *)&ihdr,hdr_len,0,(sockaddr *)&addrsrv,sizeof(addrsrv)) == -1)
165         {
166             --sndcnt;
167             continue;
168         }
169         
170         int  nlength    = sizeof(addrcli);
171         timeout.tv_sec  = 3000;  
172         timeout.tv_usec = 0;
173 
174         setsockopt(soc, SOL_SOCKET,SO_RCVTIMEO, (char*)&timeout,sizeof(timeout));
175 
176         if(recvfrom(soc,recv,PACKETSIZE,0,(sockaddr *)&addrcli,&nlength) == -1)
177         {
178             printf("请求超时!\n");
179             ++loscnt;
180             continue;
181         }
182 
183         iphdr* piphdr = (iphdr *)recv;
184         if(checksum(piphdr->ip_hdr_len << 2,(unsigned short *)piphdr) != 0)
185         {
186             printf("invalid ip packet!\n");
187             continue;
188         }
189 
190         icmphdr* pichdr = (icmphdr *)(piphdr + 1);
191         if(checksum(hdr_len,(unsigned short *)pichdr) != 0)
192         {
193             printf("invalid icmp packet!\n");
194             continue;
195         }
196     
197         interval = getsystickcount64() - pichdr->icmp_timestamp;
198         avgdelay+= interval;
199 
200         maxdelay = interval > maxdelay ? interval : maxdelay;
201         mindelay = interval > mindelay ? mindelay : interval;
202         
203         printf("来自 %s 的回复: 字节=%d 时间=%dms TTL=%u\n",inet_ntoa(addrsrv.sin_addr),payload + sizeof(LONGLONG),interval,piphdr->ip_ttl);
204 
205         Sleep(1000);
206     }
207 
208     printf("\n");
209     printf("%s 的 Ping 统计信息: \n",inet_ntoa(addrsrv.sin_addr));
210     printf("    数据包: 已发送 = %d, 已接收 = %d, 丢失 = %d (%.2f%% 丢失),\n",sndcnt,sndcnt-loscnt,loscnt,(loscnt * 100) / (double)sndcnt);
211     printf("往返行程的估计时间(以毫秒为单位):\n");
212     printf("    最短 = %dms, 最长 = %dms, 平均 = %dms\n",mindelay,maxdelay,avgdelay / sndcnt);
213     printf("\n");
214 }
215 
216 int main(int argc,char * argv[])
217 {
218     ping("www.baidu.com",1464,4);
219     return 0;
220 }

 

  

 

posted on 2016-11-11 10:32  gtxvs  阅读(642)  评论(0编辑  收藏  举报