
- /*
- 导入库文件
- */
- #pragma comment( lib,"ws2_32.lib")
- //加载头文件
- #include <WinSock2.h>
- #include <WS2tcpip.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
-
- //定义常量
- //表示要记录的路由
- #define IP_RECORD_ROUTE 0x7
- //默认数据报的大小
- #define DEF_PACKET_SIZE 32
- //最大的ICMP数据报大小
- #define MAX_PACKET 1024
- //最大的ip头长度
- #define MAX_IP_HDR_SIZE 60
- //icmp报文类型,回显请求
- #define ICMP_ECHO 8
- //ICMP报文类型,回显应答
- #define ICMP_ECHO 0
- //最小的ICMP数据报大小
- #define ICMP_ECHOREPLY 8
- //自定义函数
- void InitPing();
-
- typedef struct _iphdr {
- unsigned int h_len : 4; //IP报头的长度
- unsigned int version:4; //IP的版本号
- unsigned char tos; //服务类型
- unsigned short total_len; //数据报的总长度
- unsigned short ident; //唯一的标识符
- unsigned short frag_flags; //分段标志
- unsigned char ttl; //生存期
- unsigned char proto; //协议类型(TCP,UDP)
- unsigned short checksum; //校验和
- unsigned int sourceIP; //源ip地址
- unsigned int destIP; //目的ip地址
- }IpHeader;
-
- //ICMP报头的字段的数据结构
- typedef struct _icmphdr
- {
- BYTE i_type; //ICMP报文类型
- BYTE i_code; //该类型中的代码号
- USHORT i_cksum; //校验和
- USHORT i_id; //唯一的标识符
- USHORT i_seq; //序列号
- USHORT timestamp; //时间戳
- }IcmpHeader;
- //IP选项头字段数据结构
- typedef struct _ipoptionhdr {
- unsigned char code; //选项类型
- unsigned char len; //选项头长度
- unsigned char ptr; //地址偏移长度
- unsigned long addr[9]; //记录的ip地址列表
-
- }IpOptionHeader;
- //定义全局变量
- SOCKET m_socket;
- IpOptionHeader IpOption;
- SOCKADDR_IN DestAddr;
- SOCKADDR_IN SourceAddr;
- char* icmp_data;
- char* recvbuf;
- USHORT seq_no;
- char* lpdest;
- int datasize;
- BOOL RecordFlag;
- double PacketNum;
- BOOL SucessFlag;
-
- //下面开始函数
- //初始化函数
- void InitPing()
- {
- WSADATA wsaData;
- icmp_data = NULL;
- seq_no = 0;
- recvbuf = NULL;
- RecordFlag = FALSE;
- lpdest = NULL;
- datasize = DEF_PACKET_SIZE;
- PacketNum = 5;
- SucessFlag = FALSE;
-
- //winsock初始化 WSAAccept 对winsocket进行加载
- if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
- {
- //如果初始化不成功则报错
- printf("WSAStartup() failed: %d\n",GetLastError());
- return;
- }
- m_socket = INVALID_SOCKET;
- }
-
-
- /*显示信息函数*/
- void UserHelp() {
- printf("UserHelp: ping -r <host> [data size] \n");
- printf(" -r record route \n");
- printf(" -n record amount \n");
- printf(" host remote machine to ping \n");
- printf(" datasize can be up to 1KB\n");
-
- }
- /*获取ping选项函数*/
- void GetArgments(int argc,char** argv) {
- int i;
- int j;
- int exp;
- int len;
- int m;
- //如果没有指定目的地址和任何选项
- if (argc==1)
- {
- printf("\nPlease specify the destination IP address and the ping option as follow!\n");
- for (i = 0; i < argc; i++)
- {
- len = strlen(argv[i]);
- if (argv[i][0] == '-')
- {
- //选项指令要获取记录条数
- if (isdigit(argv[i][1]))
- {
- PacketNum = 0;
- for (j = len-1,exp=0; j >= 1; j--,exp++)
- {
- //根据argv[i][j]中的ASCII值计算要获取的记录条数(十进制数)
- PacketNum += ((double)(argv[i][j] - 48)) * pow(10, exp);
- }
- }
- else
- {
- switch (tolower(argv[i][1]))
- {
- //选项指令要获取路由信息
- case 'r':
- RecordFlag = TRUE;
- break;
- //没有按要求提供选项
- default:
- UserHelp();
- break;
- }
- }
- }
- //参数是数据报大小或者IP地址
- else if(isdigit(argv[i][0]))
- {
- for (m = 0; m < len; m++)
- {
- if (!isdigit(argv[i][m]))
- {
- //是IP地址
- lpdest = argv[i];
- break;
- }
- //是数据报大小
- else if (m == len - 1)
- datasize = atoi(argv[i]);
- }
- }
- //参数是主机名
- else
- {
- lpdest = argv[i];
- }
-
- }
- }
- }
-
- //求校验和函数
-
- USHORT CheckSum(USHORT* buffer,int size)
- {
- unsigned long cksum = 0;
- while (size>1)
- {
- cksum += *buffer++;
- size -= sizeof(USHORT);
- }
- if (size)
- {
- cksum += *(UCHAR*)buffer;
- }
- //每16位取二进制反码求和
- cksum = (cksum >> 16) + (cksum & 0xffff);
- cksum += (cksum >> 16);
- return (USHORT)(~cksum);
- }
- //填充ICMP数据报字段函数
- void FillICMPData(char *icmp_data,int datasize)
- {
- IcmpHeader* icmp_hdr = NULL;
- char* datapart = NULL;
- icmp_hdr = (IcmpHeader*)icmp_data;
- //ICMP报文类型设置为回显请求
- icmp_hdr->i_type = ICMP_ECHO;
- icmp_hdr->i_cksum = 0;
- //获取当前经常IP作为标识符
- icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
- icmp_hdr->i_cksum = 0;
- icmp_hdr->i_seq = 0;
- datapart = icmp_data + sizeof(IcmpHeader);
- //以数字0天吃剩余空间
- memset(datapart, 0, datapart - sizeof(IcmpHeader));
- }
- //释放资源函数
- void FreeRes()
- {
- //关闭创建的套字节
- if (m_socket!=INVALID_SOCKET)
- {
- closesocket(m_socket);
- }
- //释放分配的内存
- HeapFree(GetProcessHeap(), 0, recvbuf);
- HeapFree(GetProcessHeap(), 0, icmp_data);
- //注销WSAStartup()调用
- WSACleanup();
- return;
- }
- //解读Ip选项头函数
- void DecoideIPptions(char *buf,int bytes)
- {
- IpOptionHeader* ipopt = NULL;
- IN_ADDR inaddr;
- int i;
- HOSTENT* host = NULL;
- //获取路由信息的入口地址
- ipopt = (IpOptionHeader*)(buf + 20);
- printf(" RR: ");
- for (i = 0; i < (ipopt->ptr / 4) - 1; i++)
- {
- inaddr.S_un.S_addr = ipopt->addr[i];
- if (i!=0)
- {
- printf(" ");
- //根据IP地址获取主机名
- host = gethostbyaddr((char*)& inaddr.S_un.S_addr, sizeof(inaddr.S_un.S_addr), AF_INET);
- }
- //如果获取到了主机名,则输出主机名
- if (host)
- {
- printf("(%-15s) %s\n",inet_ntoa(inaddr),host->h_name);
- }
- else
- {
- //否则输出ip地址
- printf("(%-15s)\n", inet_ntoa(inaddr));
- }
- return;
- }
- }
- //解读ICMP报头函数
- void DecodeICMPHeader(char* buf,int bytes,SOCKADDR_IN* from)
- {
- IpHeader* iphdr = NULL;
- IcmpHeader* icmphdr = NULL;
- unsigned short iphdrlen;
- DWORD tick;
- static int icmpcount = 0;
- iphdr = (IpHeader*)buf;
- //计算ip报头的长度
- iphdrlen = iphdr->h_len * 4;
- tick = GetTickCount();
- //如果ip报头的长度为最大长度(基本长度是20字节),则认为有ip选项,因此需要解读ip选项
- if ((iphdrlen==MAX_IP_HDR_SIZE)&&(!icmpcount))
- {
- //解读IP选项,即路由信息
- DecoideIPptions(buf,bytes);
- }
- //如果收到的不是回显应答的报文则报错
- if (icmphdr->i_id != ICMP_ECHOREPLY)
- {
- printf("nonecho type %d recvd \n",icmphdr->i_type);
- return;
- }
- //核实用收到的ID号和发送的是否一致
- if (icmphdr->i_id != (USHORT)GetCurrentProcessId())
- {
- printf("someone else's packet! \n");
- return;
- }
- //输出信息记录信息
- printf("%d bytes from %s:",bytes,inet_ntoa(from->sin_addr));
- printf(" icmp_seq =%d. ", icmphdr->i_seq);
- printf(" icmp_seq =%d. ", tick - icmphdr->timestamp);
- printf("\n");
- icmpcount++;
- return;
- }
- //ping 函数
- void PingTest(int timeout)
- {
- int ret;
- int readNum;
- int fromlen;
- struct hostent* hp = NULL;
- //创建原始套接字,该套接字用于ICMP
- m_socket = WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);
- //如果套接字创建不成功
- if (m_socket==INVALID_SOCKET)
- {
- printf("WSASocket() Failed: %d \n",WSAGetLastError());
- return;
- }
- //要求记录路由选项
- if (RecordFlag)
- {
- //IP选项每个字段都初始化为零
- ZeroMemory(&IpOption, sizeof(IpOption));
- //为每一个ICMP包设置路由选项
- IpOption.code = IP_RECORD_ROUTE;
- IpOption.ptr = 4;
- IpOption.len = 39;
- ret = setsockopt(m_socket, IPPROTO_IP, IP_OPTIONS, (char*)& IpOption, sizeof(IpOption));
- if (ret==SOCKET_ERROR)
- {
- printf("setsockopt(IP_OPTIONS) failed:%d \n",WSAGetLastError());
- }
- }
- //设置接收的超时值
- readNum = setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (char*)& timeout, sizeof(timeout));
- if (readNum==SOCKET_ERROR)
- {
- printf("setsockopt(SO_RCVTIMEO) failed:%d\n ", WSAGetLastError());
- return;
- }
- //初始化目的的地址为零
- memset(&DestAddr, 0, sizeof(DestAddr));
- //设置地址族,这里表示使用IP地址族
- DestAddr.sin_family = AF_INET;
- if ((DestAddr.sin_addr.S_un.S_addr= inet_addr(lpdest)) == INADDR_NONE)
- {
- //名字解析,根据主机名获取IP地址
- if ((hp=gethostbyname(lpdest))!=NULL)
- {
- //将获取到的IP地址赋值给目的地址中相对应的字段
- memcpy(&(DestAddr.sin_addr), hp->h_addr_list, hp->h_length);
- //将获取到的地址族群赋值到目的相对应的字段中
- DestAddr.sin_family = hp->h_addrtype;
- printf("DestAddr.sin_addr = %s \n",WSAGetLastError());
- }
- //获取不成功
- else
- {
- printf("gethostbyname() faild: %d \n ",WSAGetLastError());
- return;
- }
- }
- //数据报文需要包含ICMP报头
- datasize += sizeof(IcmpHeader);
- //根据默认堆句柄,从堆中分配MAX_PACKET内存块,新分配内存将初始化为零
- icmp_data = (char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);
- recvbuf = (char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);
- //如果奉陪内存不成功
- if (!icmp_data)
- {
- printf("HeapAlloc() failed: %d \n", GetLastError());
- return;
- }
- //创建ICMP报文
- memset(icmp_data, 0, MAX_PACKET);
- FillICMPData(icmp_data, datasize);
- while (1)
- {
- static int nCount = 0;
- int writeNum;
- //超过指定的记录条数则退出
- if (nCount++ == PacketNum)
- {
- break;
- }
- //计算校验和前要把校验和字节设置为零
- ((IcmpHeader*)icmp_data)->i_cksum = 0;
- //获取操作系统启动到现在所经过的毫秒数,设置时间搓
- ((IcmpHeader*)icmp_data)->timestamp= GetTickCount();
- //设置序列号
- ((IcmpHeader*)icmp_data)->i_seq = seq_no++;
- //计算校验和
- ((IcmpHeader*)icmp_data)->i_cksum= CheckSum((USHORT*)icmp_data,datasize);
- //开始发送ICMP请求
- writeNum = sendto(m_socket,icmp_data,datasize,0,(struct sockaddr*)&DestAddr,&fromlen);
- //如果接收不成功
- if (readNum==SOCKET_ERROR)
- {
- //如果超时则不成功
- if (WSAGetLastError()==WSAETIMEDOUT)
- {
- printf("timed out \n");
- continue;
- }
- //其他发送不成功的原因
- printf("sendto() failed:%d \n",WSAGetLastError());
- return;
- }
- //开始接收ICMP应答
- fromlen = sizeof(SourceAddr);
- readNum = recvfrom(m_socket,recvbuf,MAX_PACKET,0,(struct sockaddr*)&SourceAddr,&fromlen);
- if (readNum == SOCKET_ERROR)
- {
- //如果超时则不成功
- if (WSAGetLastError() == WSAETIMEDOUT)
- {
- printf("timed out \n");
- continue;
- }
- //其他发送不成功的原因
- printf("recvfrom() failed:%d \n", WSAGetLastError());
- return;
- }
- //解读收到的ICMP数据报
- }
-
- }
-
- int main(int argc,char* argv[])
- {
- InitPing();
- GetArgments(argc,argv);
- PingTest(1000);
- //延迟1s
- Sleep(1000);
- if (SucessFlag)
- {
- printf("\n Ping end,you have got %.0f records! \n",PacketNum);
- }
- else
- {
- printf("Ping end ,no record");
- }
- FreeRes();
- getchar();
- return 0;
-
- /*
-
-
- */
- }
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739
评价
排名
2
文章
634
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 :
好是好,这个对效率影响大不大哇,效率高不高
一个bug让程序员走上法庭 索赔金额达400亿日元
剑轩 : 有点可怕
ASP.NET Core 服务注册生命周期
剑轩 :
http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:
50010702506256


欢迎加群交流技术