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

简介: 计算机网络的一个作业:实现ping+ip 不要求其它参数 用到的知识:ip报头结构,icmp报头结构,获取主机ip方法,winsock的简单操作 实现的结果:一般的ip能够ping通,如www.baidu.

计算机网络的一个作业:实现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 }

 

目录
相关文章
|
8天前
|
Ubuntu Linux
Linux 各发行版安装 ping 命令指南
如何在不同 Linux 发行版(Ubuntu/Debian、CentOS/RHEL/Fedora、Arch Linux、openSUSE、Alpine Linux)上安装 `ping` 命令,详细列出各发行版的安装步骤和验证方法,帮助系统管理员和网络工程师快速排查网络问题。
76 20
|
1月前
|
Linux iOS开发 网络架构
如何使用 Ping 命令监测网络丢包情况?
如何使用 Ping 命令监测网络丢包情况?
257 48
|
1月前
|
Linux iOS开发 MacOS
如何设置 Ping 命令的超时时间?
如何设置 Ping 命令的超时时间?
141 2
|
1月前
|
运维 监控 Linux
别再只会使用简单的 ping 命令了,Linux 中这些高级 ping 命令可以提高工作效率!
在 Linux 系统中,ping 命令不仅用于检测网络连通性和延迟,还拥有多种高级选项和技巧,如定制数据包大小、获取详细统计信息、持续 ping、指定源地址和多目标 ping。本文详细介绍这些高级命令及其在性能测试、故障排查和网络监控中的实际应用,帮助你提升网络管理效率。
144 3
|
1月前
|
Linux 网络安全 Android开发
高级 ping 命令及技巧
Ping命令是一种常用的网络诊断工具,用于测试网络连接的可达性和延迟等信息
91 1
|
1月前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
93 3
|
2月前
|
Python 机器学习/深度学习 人工智能
手把手教你从零开始构建并训练你的第一个强化学习智能体:深入浅出Agent项目实战,带你体验编程与AI结合的乐趣
【10月更文挑战第1天】本文通过构建一个简单的强化学习环境,演示了如何创建和训练智能体以完成特定任务。我们使用Python、OpenAI Gym和PyTorch搭建了一个基础的智能体,使其学会在CartPole-v1环境中保持杆子不倒。文中详细介绍了环境设置、神经网络构建及训练过程。此实战案例有助于理解智能体的工作原理及基本训练方法,为更复杂应用奠定基础。首先需安装必要库: ```bash pip install gym torch ``` 接着定义环境并与之交互,实现智能体的训练。通过多个回合的试错学习,智能体逐步优化其策略。这一过程虽从基础做起,但为后续研究提供了良好起点。
203 4
手把手教你从零开始构建并训练你的第一个强化学习智能体:深入浅出Agent项目实战,带你体验编程与AI结合的乐趣
|
1月前
|
存储 安全 数据库
适用于 Windows 的管理命令
以下命令可用于管理 Rational® Synergy。
18 1
|
2月前
|
人工智能 监控 安全
掌握Windows管理利器:WMI命令实战
本文介绍了Windows Management Instrumentation (WMI) 的基本概念和用途,通过多个实用的`wmic`命令示例,如获取CPU信息、查看操作系统详情、管理服务、检查磁盘空间等,展示了WMI在系统维护中的强大功能。适合IT专业人士学习和参考。
78 4
|
2月前
|
弹性计算 安全 Linux
阿里云国际版使用ping命令测试ECS云服务器不通的排查方法
阿里云国际版使用ping命令测试ECS云服务器不通的排查方法

热门文章

最新文章