简单的实现了一个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 }