自己动手写一个简单的ping命令(windows下)

计算机网络的一个作业:实现ping+ip 不要求其它参数

用到的知识:ip报头结构,icmp报头结构,获取主机ip方法,winsock的简单操作

实现的结果:一般的ip能够ping通,如www.baidu.com, www.sina.com.cn

存在的问题:本机(127.0.0.1)ping不通  

  1 /*
  2 *filename:ping.c
  3 *author:ChrisZZ
  4 */
  5 #pragma comment(lib, "ws2_32.lib")
  6 #include <stdio.h>
  7 #include <winsock2.h>
  8 #include <ws2tcpip.h>
  9 #include <process.h>
 10
 11
 12 struct IPHeader{//IPv4头部结构
 13     unsigned char ver_hlen;//头部长度,用4位表示,range[5,15]
 14     //  unsigned int ver:4;//version
 15     unsigned char tos;//type of service
 16     unsigned short total_len;
 17     unsigned short id;
 18     unsigned short frags_and_flags;
 19     unsigned char ttl;//time to live
 20     unsigned char proto;//protocal
 21     unsigned short chksum;//checksum
 22     unsigned int srcIp;//source IP
 23     unsigned int dstIp;//destination IP
 24 };
 25
 26 struct ICMPHeader{//ICMP头部结构
 27     unsigned char type;
 28     unsigned char code;
 29     unsigned short chksum;
 30     unsigned short id;
 31     unsigned short seq;//sequence
 32     unsigned int timestamp;
 33 };
 34
 35 #define ICMP_ECHO       8
 36 #define ICMP_ECHO_REPLY 0
 37 #define  PACKAGE_SIZE         sizeof(IPHeader)+sizeof(ICMPHeader)
 38 void usage();
 39 unsigned short CheckSum(unsigned short*, int);
 40 void HandleError(char *);
 41
 42 //用法说明函数
 43 void usage(){
 44     printf("用法:ping 目标主机\n\n");
 45     system("pause");
 46 }
 47
 48 //错误处理函数
 49 void HandleError(char *str){
 50     int errCode=WSAGetLastError();
 51
 52     char info[65]={0};
 53     _snprintf(info, 64, "%s:  %d\n", str, errCode);
 54     printf(info);
 55 }
 56
 57 unsigned short checksum(unsigned short* buff, int size){
 58     unsigned int chksum=0;
 59     while(size>1){
 60         chksum+=*buff++;
 61         size-=sizeof(unsigned short);
 62     }
 63     if(size){
 64         chksum+=*(unsigned char*)(buff);
 65     }
 66     chksum=(chksum>>16)+(chksum &0xffff);
 67     chksum+=(chksum>>16);
 68     return (unsigned short)(~chksum);
 69 }
 70
 71 void FillPackage(char *pData, unsigned int dstIP, unsigned short id){
 72     memset(pData, 0, PACKAGE_SIZE);
 73
 74     IPHeader *pIPHeader=(IPHeader*)pData;
 75
 76     int nVersion=4;
 77     int nHeadSize=sizeof(IPHeader)/4;
 78
 79     //获得本机IP
 80     struct sockaddr_in SrcAddr;
 81     struct hostent * hpsrc;
 82     char localhost[32];
 83     gethostname(localhost, sizeof(localhost));
 84     hpsrc=gethostbyname(localhost);
 85     memset(&SrcAddr, 0, sizeof(SrcAddr));
 86     memcpy(&(SrcAddr.sin_addr), hpsrc->h_addr, hpsrc->h_length);
 87     SrcAddr.sin_port=htons(0);
 88     SrcAddr.sin_family=AF_INET;
 89
 90
 91     unsigned int srcIP=SrcAddr.sin_addr.s_addr;//本机IP
 92     unsigned int destIp=dstIP;
 93     pIPHeader->ver_hlen=(nVersion<<4)|nHeadSize;
 94     pIPHeader->tos=0;
 95     pIPHeader->total_len=htons(PACKAGE_SIZE);
 96     pIPHeader->id=htons(1234);//????
 97     pIPHeader->frags_and_flags=0;
 98     pIPHeader->ttl=255;//??
 99     pIPHeader->proto=IPPROTO_ICMP;
100     pIPHeader->chksum=0;
101     pIPHeader->srcIp=srcIP;
102     pIPHeader->dstIp=dstIP;
103
104     pIPHeader->chksum=checksum((unsigned short*)pData, sizeof(IPHeader));
105     ICMPHeader* pICMPHeader=(ICMPHeader*)(pData+sizeof(IPHeader));
106     pICMPHeader->type=ICMP_ECHO;
107     pICMPHeader->code=0;
108     pICMPHeader->chksum=0;
109     pICMPHeader->id=htons(id);
110     pICMPHeader->seq=htons(id);
111     pICMPHeader->chksum=checksum((unsigned short*)((char*)pData+sizeof(IPHeader)), sizeof(ICMPHeader));
112
113 }
114
115 int main(int argc, char* argv[]){
116
117     //初始化
118     WSADATA wsaData;
119     struct sockaddr_in DestAddr,from;
120     IPHeader *ip;
121     ICMPHeader *icmp;
122     ICMPHeader *SendIcmp;
123     int Timeout=1000;
124     char IcmpBuffer[PACKAGE_SIZE]="";
125     SOCKET IcmpSocket;
126     char RecvBuffer[1024];
127     sockaddr_in addr;
128     int Len = sizeof(addr);
129     int Result;
130     struct hostent * hpdst;
131     int pid=_getpid();
132     struct timeval tv;
133     fd_set readSet;
134     BOOL bBroadcast=false;
135
136     //确定参数个数
137     if(argc!=2){
138         printf("参数不正确\n");
139         usage();
140         return -1;
141     }
142
143
144     if ((Result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0){
145         printf("WSAStartup failed with error %d\n", Result);
146         return 0;
147     }
148
149
150     //获取目的主机IP
151     hpdst=gethostbyname(argv[1]);
152     if(hpdst==NULL){
153         HandleError("gethostbyname");
154         WSACleanup();
155         return -1;
156     }
157
158     //创建ICMP封包并发送
159     //char buff[sizeof(ICMP_HDR)+32];
160     IcmpSocket=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
161     if(IcmpSocket==INVALID_SOCKET){
162         HandleError("socket");
163         WSACleanup();
164         return -1;
165     }
166     BOOL on=TRUE;
167     Result=setsockopt(IcmpSocket,IPPROTO_IP,IP_HDRINCL, (char*)&on, sizeof(on));
168     if(Result==SOCKET_ERROR){
169         HandleError("socketopt");
170         WSACleanup();
171         return -1;
172     }
173     memset(&DestAddr, 0, sizeof(DestAddr));
174     memcpy(&(DestAddr.sin_addr), hpdst->h_addr, hpdst->h_length);
175     DestAddr.sin_port=htons(0);
176     /*reference:http://www.cnblogs.com/CBDoctor/archive/2012/10/28/2743109.html*/
177     DestAddr.sin_family=AF_INET;
178
179
180
181     int i;
182     for(i=0; i<3; i++){
183        if(i==0) printf("正在Ping %s 具有 %d 字节的数据:\n", inet_ntoa(DestAddr.sin_addr), 32);
184
185         FillPackage(IcmpBuffer, DestAddr.sin_addr.s_addr/*dstIp*/, (unsigned short)pid);
186
187         Result=sendto(IcmpSocket, IcmpBuffer, PACKAGE_SIZE, 0, (struct sockaddr*)&DestAddr, sizeof(DestAddr));
188         if(Result==SOCKET_ERROR){
189             HandleError("sendto");
190             break;
191         }
192
193         while (1){
194             tv.tv_sec=3;
195             tv.tv_usec=0;
196             FD_ZERO(&readSet);
197             FD_SET(IcmpSocket,&readSet);
198
199             int res=select(IcmpSocket+1,&readSet,NULL,NULL,&tv);
200             if(res==SOCKET_ERROR){
201                 HandleError("select");
202                 break;
203             }
204             if(res==0){
205                 if(!bBroadcast)
206                     printf("请求超时。\n");
207                 break;
208             }
209             if(FD_ISSET(IcmpSocket, &readSet)){
210                 memset(IcmpBuffer,0, PACKAGE_SIZE);
211                 memset(&from,0,sizeof(from));
212                 int len=sizeof(from);
213                 if(recvfrom(IcmpSocket, IcmpBuffer, PACKAGE_SIZE,0,(struct sockaddr*) &from, &len)==SOCKET_ERROR)
214                 {
215                     HandleError("recvfrom");
216                     break;
217                 }
218
219                 IPHeader *pIPHdr=(IPHeader *) IcmpBuffer;
220                 ICMPHeader *pICMPHdr=(ICMPHeader*)(IcmpBuffer+sizeof(IPHeader));
221                 int nTime = GetTickCount() - pICMPHdr->timestamp;
222                 if(pICMPHdr->id==htons((u_short) pid)&&pICMPHdr->seq==htons((u_short) pid)
223                     &&pICMPHdr->type==ICMP_ECHO_REPLY){
224                         printf("来自 %s 的回复: 字节=%d time=%dms\n",inet_ntoa(from.sin_addr), Result, pIPHdr->ttl);
225                         if (!bBroadcast) break;
226                 }
227             }
228         }//end of while
229         Sleep(1000);
230     }
231
232     //关闭套接字
233     closesocket(IcmpSocket);
234     WSACleanup();
235     system("pause");
236     return 0;
237 }

 

时间: 2024-09-21 07:32:52

自己动手写一个简单的ping命令(windows下)的相关文章

自己动手写一个java版简单云相册_java

动手写一个java版简单云相册,实现的功能是: 用户可以一次上传一个至多个文件. 用户可以下载其他人上传的图片. 用户可以查看其他所有人的图片. 用户只能删除通过自己IP上传的图片. 用到的技术: 文件上传下载.设计模式.Dom4j.xPath等. 先看下2个页面: 源代码: web.xml: <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns=

unix-Solaris 10 写一个脚本,在atc用户下,调用该脚本,执行poweroff命令

问题描述 Solaris 10 写一个脚本,在atc用户下,调用该脚本,执行poweroff命令 Solaris 10 写一个脚本,在atc用户下,调用该脚本,执行poweroff命令 解决方案 实现一个脚本,然后atc用户执行 解决方案二: 实现一个脚本,然后atc用户执行

请大神帮忙写一个简单的聚类算法程序,在线等……用matlab或者java实现

问题描述 请大神帮忙写一个简单的聚类算法程序,在线等--用matlab或者java实现 Step1:将N个数据,按照从小到大的顺序排序 d1.d2,.....dn:其中d1时最小值,dn是最大值 聚类判别阈值计算方法为: Step2:让每个数据都作为一个类,那么有 {d1},{d2},{d3},.....{dn} Step3:计算聚类中心 假设共有P个类,那么1<=k<=P,其中r代表每个类中数据的个数,同时计算相邻两个聚类中心之间的距离,如下 Step4:找出相邻两个聚类中心的最小值 Ste

java中用集合写一个简单的登录功能。麻烦大家看一看

问题描述 java中用集合写一个简单的登录功能.麻烦大家看一看 //这是注册的方法 public static void reg(){ Collection id=new ArrayList();//账户 Collection passWord=new ArrayList();//密码 Scanner sc=new Scanner(System.in); System.out.println("请输入账号:"); id.add(sc.next()); System.out.printl

学习servlet,写一个简单的Helloword出现404错误

问题描述 学习servlet,写一个简单的Helloword出现404错误 解决方案 不需要 /servlet 解决方案二: 解决方案三: web.xml内容贴下来看看. 可以参考 我写的http://blog.csdn.net/evankaka/article/details/45151569 解决方案四: url里把[/Hello]改成[/HelloServlet] 和你Web.xml里配置的url-pattern一样. 解决方案五: 一个简单的Servlet 解决方案六: 采用servle

iis-用VisualStudio2012写一个简单的网站

问题描述 用VisualStudio2012写一个简单的网站 用VisualStudio2012写一个简单的网站,主要想学一下怎么用VS写网站.IIS安装好了用http://localhost打不开,百度方法用遍了都没解决,就没有一个会的么?!

springmvc-用jsp写一个简单的登录页面

问题描述 用jsp写一个简单的登录页面 求写一个登录页面,有form表单,然后能提交到数据库.框架是spring,数据库是sql,用java,jsp写..我是新手,所以恳求大神帮帮我.非常感谢谢.. 解决方案 form表单里面放输入框组,用于填写数据,像登陆这种涉及隐私的操作,最好使用post方式提交, 在action层,我看到你只提到了spring,那就直接servlet来接收数据进行处理,在doPost中通过request.getParameter(str)获取参数,经过一系列校验之后,就可

c++-写一个简单的二叉树遇到了segmentation fault :11问题,求助

问题描述 写一个简单的二叉树遇到了segmentation fault :11问题,求助 本人小白,写了个简单的二叉树练习一下,代码如下,运行时会出现segmentation fault :11错误,求助各位大大帮忙看看是什么原因? #include <iostream> #include <fstream> using namespace std; class Node { private: int content; Node *left; Node *right; public

checkbox-刚学完JS和servlet,写一个简单的注册登录页面

问题描述 刚学完JS和servlet,写一个简单的注册登录页面 ,想把checkbox选中的的数据和下拉列表选中的的年月日组合成字符串发送给servlet,该怎么做,求大神指教 解决方案 username: password: 表单 action 对应的servlet method 提交方式,对应servlet的doPost和doGet方法 在servlet中写 req.getParameter("username"); req.getParameter("password&