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

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

 #pragma pack(4)

 #define  ECHO_REQUEST        8
#define DATASIZE 65500
#define PACKETSIZE 65535 struct iphdr
{
unsigned char ip_hdr_len : ; //包头长度
unsigned char ip_version : ; //版本
unsigned char ip_tos; unsigned short ip_length; //总长度
unsigned short ip_identify;//标识
unsigned short ip_offset;//片偏移
unsigned char ip_ttl;
unsigned char ip_protocol;
unsigned short ip_cksum; struct in_addr ip_src; //源地址
struct in_addr ip_dst; //目的地址
}; struct icmphdr
{
unsigned char icmp_type; //8位类型
unsigned char icmp_code; //8位代码
unsigned short icmp_cksum; //16位的校验和 unsigned short icmp_identify;
unsigned short icmp_seq; LONGLONG icmp_timestamp;
char icmp_data[DATASIZE];
}; unsigned short checksum(int count,unsigned short* addr)
{
long sum = ; while(count > )
{
sum +=*addr++;
count -= sizeof(unsigned short);
} if(count > )
{
sum +=*(unsigned char*)addr;
} while(sum >> )
{
sum = (sum & 0xFFFF) + (sum >> );
} return (unsigned short)(~sum);
} void packet_pad(char * buf,int payload)
{
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"; int size = sizeof(pad) -;
int count = payload / size;
int remain = payload % size;
int offset = ; //偏移 memset((void *)buf,,payload); for(int i = ;i < count; ++i)
{
memcpy((void *)(buf + offset),(void *)pad,size);
offset += size;
} memcpy((void *)(buf + offset),(void *)pad,remain);
} LONGLONG getsystickcount64()
{
static LARGE_INTEGER tickspersecond = {};
LARGE_INTEGER tick; if(!tickspersecond.QuadPart)
{
QueryPerformanceFrequency(&tickspersecond);
} QueryPerformanceCounter(&tick); LONGLONG seconds = tick.QuadPart / tickspersecond.QuadPart;
LONGLONG leftPart = tick.QuadPart - (tickspersecond.QuadPart * seconds);
LONGLONG millseconds = ((leftpart << ) - ((leftpart << ) + (leftpart << ))) / tickspersecond.QuadPart;
LONGLONG ret = ((seconds << ) - ((seconds << ) + (seconds << ))) + millseconds; return ret;
}; bool ping(char * target,int payload,int count)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(, ), &wsaData); SOCKET soc = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
if(soc == -)
{
printf("create raw socket failed!\n");
return false;
} if(payload > DATASIZE)
{
printf("发送的字节数有错误,有效范围从 0 到 %d",DATASIZE);
return false;
} payload = payload - sizeof(LONGLONG); struct sockaddr_in addrsrv; addrsrv.sin_family = AF_INET;
addrsrv.sin_port = htons();
struct hostent* phostent = gethostbyname(target);
if (phostent)
{
addrsrv.sin_addr.s_addr = *(u_long *)phostent->h_addr_list[];
} printf("正在 Ping %s [%s] 具有 %d 字节的数据: \n",target,inet_ntoa(addrsrv.sin_addr),payload + sizeof(LONGLONG)); icmphdr ihdr = {}; memset((void *)ihdr.icmp_data,,DATASIZE);
packet_pad(ihdr.icmp_data,payload); //填充数据 ihdr.icmp_type = ECHO_REQUEST;
ihdr.icmp_identify = (unsigned short)GetCurrentProcessId(); int hdr_len = payload + sizeof(icmphdr) - DATASIZE; struct timeval timeout;
struct sockaddr_in addrcli; char recv[PACKETSIZE] = {}; unsigned long interval = ;
unsigned long avgdelay = ;
unsigned long maxdelay = ;
unsigned long mindelay = ~; unsigned int sndcnt = count;
unsigned int loscnt = ; for(int seq = ; seq < count; ++seq)
{
memset((void *)recv,,PACKETSIZE); ihdr.icmp_seq = seq;
ihdr.icmp_cksum = ;
ihdr.icmp_timestamp = getsystickcount64(); //时间戳
ihdr.icmp_cksum = checksum(hdr_len,(unsigned short *)&ihdr); if(sendto(soc,(char *)&ihdr,hdr_len,,(sockaddr *)&addrsrv,sizeof(addrsrv)) == -)
{
--sndcnt;
continue;
} int nlength = sizeof(addrcli);
timeout.tv_sec = ;
timeout.tv_usec = ; setsockopt(soc, SOL_SOCKET,SO_RCVTIMEO, (char*)&timeout,sizeof(timeout)); if(recvfrom(soc,recv,PACKETSIZE,,(sockaddr *)&addrcli,&nlength) == -)
{
printf("请求超时!\n");
++loscnt;
continue;
} iphdr* piphdr = (iphdr *)recv;
if(checksum(piphdr->ip_hdr_len << ,(unsigned short *)piphdr) != )
{
printf("invalid ip packet!\n");
continue;
} icmphdr* pichdr = (icmphdr *)(piphdr + );
if(checksum(hdr_len,(unsigned short *)pichdr) != )
{
printf("invalid icmp packet!\n");
continue;
} interval = getsystickcount64() - pichdr->icmp_timestamp;
avgdelay+= interval; maxdelay = interval > maxdelay ? interval : maxdelay;
mindelay = interval > mindelay ? mindelay : interval; printf("来自 %s 的回复: 字节=%d 时间=%dms TTL=%u\n",inet_ntoa(addrsrv.sin_addr),payload + sizeof(LONGLONG),interval,piphdr->ip_ttl); Sleep();
} printf("\n");
printf("%s 的 Ping 统计信息: \n",inet_ntoa(addrsrv.sin_addr));
printf(" 数据包: 已发送 = %d, 已接收 = %d, 丢失 = %d (%.2f%% 丢失),\n",sndcnt,sndcnt-loscnt,loscnt,(loscnt * ) / (double)sndcnt);
printf("往返行程的估计时间(以毫秒为单位):\n");
printf(" 最短 = %dms, 最长 = %dms, 平均 = %dms\n",mindelay,maxdelay,avgdelay / sndcnt);
printf("\n");
} int main(int argc,char * argv[])
{
ping("www.baidu.com",,);
return ;
}

TCP协议学习记录 (二) Ping程序-LMLPHP

04-26 00:24