实现ping命令的代码

#include    <stdio.h>
#include    <sys/time.h>
#include    <signal.h>
#include    <arpa/inet.h>
#include    <sys/types.h>
#include    <sys/socket.h>
#include    <unistd.h>
#include    <netinet/in.h>
#include    <netinet/ip.h>
#include    <netdb.h>
#include    <setjmp.h>
#include    <errno.h>
#include    <netinet/ip_icmp.h>
#include    <string.h>
#include    <stdlib.h>
#define    PACKET_SIZE 4096            /*  */
#define MAX_WAIT_TIME 5
#define MAX_NO_PACKETS 3

char sendpacket[PACKET_SIZE];
char recvpacket[PACKET_SIZE];
int sockfd,datalen=56;
int nsend=0,nreceived=0;
struct sockaddr_in dest_addr;
pid_t pid;
struct sockaddr_in from;
struct timeval tvrecv;
void statistics(int signo);
unsigned short cal_chksum(unsigned short *addr,int len);
int pack(int pack_no);
void send_packet(void);
void recv_packet(void);
int unpack(char* buf,int len);
void tv_sub(struct timeval *out,struct timeval* in);

void statistics(int signo)
{
   printf("\n-----------------PING statistics----------------\n");
   printf("%d packet transmitted,%d received,%%%d lost \n",nsend,nreceived,(nsend-nreceived)/nsend*100);
   close(sockfd);
   exit(1);
}
/*校验和算法*/
unsigned short cal_chksum(unsigned short *addr,int len)
{
   int nleft=len;
   int sum=0;
   unsigned short *w=addr;
   unsigned short answer=0;
   /*把ICMP报头二进制数据以2字节为单位累加起来*/
   while(nleft>1)
   {
       sum+=*w++;
       nleft-=2;
   }
   /*若ICMP报头为奇数个字节,会剩下最后一个字节。把最后一个字节视为2字节数据的高字节,这个2字节数据的低字节为0,继续累加*/
   if(nleft==1)
   {
       *(unsigned char *)(&answer)=*(unsigned char *)w;
       sum+=answer;
   }
   sum=(sum>>16)+(sum&0xffff);
   sum+=(sum>>16);
   answer=~sum;
   return answer;
}
/*设置ICMP报头*/
int pack(int pack_no)
{
   int packsize;
   struct icmp *icmpp;
   struct timeval *tval;
   icmpp=(struct icmp *)sendpacket;
   icmpp->icmp_type=ICMP_ECHO;
   icmpp->icmp_code=0;
   icmpp->icmp_cksum=0;
   icmpp->icmp_seq=pack_no;
   icmpp->icmp_id=pid;
   packsize=8+datalen;
   tval=(struct timeval *)icmpp->icmp_data;
   gettimeofday(tval,NULL);/*记录发送时间*/
   icmpp->icmp_cksum=cal_chksum((unsigned short*)icmpp,packsize);/*校验算法*/
   return packsize;
}
/*发送3个ICMP报文*/
void send_packet()
{
   int packetsize;
   while(nsend<MAX_NO_PACKETS)
   {
       nsend++;
       packetsize=pack(nsend);/*设置ICMP报文*/
       if(sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr))<0)
       {
           perror("sendto error");
           continue;
       }
       sleep(1);/*每隔一秒发送一个ICMP报文*/
   }
}
/*接收所有ICMP报文*/
void recv_packet()
{
   int n,fromlen;
   extern int errno;
  /*更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/cplus/*/
   signal(SIGALRM,statistics);
   fromlen=sizeof(from);
   while(nreceived<10)
   {
       alarm(MAX_WAIT_TIME);
       if((n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen))<0)
       {
           if(errno==EINTR)
           {
               continue;
           }
           perror("recvfrom error\n");
           continue;
       }
       gettimeofday(&tvrecv,NULL); /*记录接收时间*/
       if(unpack(recvpacket,n)==-1)
           continue;
       nreceived++;
   }
}
/*剥去ICMP报头*/
int unpack(char *buf,int len)
{
   int iphdrlen;
   struct ip *ipp;
   struct icmp *icmpp;
   struct timeval *tvsend;
   int rtt;
   ipp=(struct ip *)buf;
   iphdrlen=(ipp->ip_hl)*4;/*求IP报头长度,即IP报头的长度标志乘4*/
   icmpp=(struct icmp*)(buf+iphdrlen);/*超过IP报头,指向ICMP报头*/
   len-=iphdrlen;/*ICMP报头及ICMP数据报的总长度*/
   if(len<8)/*小于ICMP报头长度则不合理*/
   {
       printf("ICMP packets\'s length is less than 8\n");
       return -1;
   }
   /*确保所接收的是用户所发的ICMP的回应*/
   if((icmpp->icmp_type==ICMP_ECHOREPLY)&&(icmpp->icmp_id==pid))
   {
       tvsend=(struct timeval *)icmpp->icmp_data;
       tv_sub(&tvrecv,tvsend); /*接收和发送的时间差*/
       rtt=tvrecv.tv_sec*1000+tvrecv.tv_usec/1000;/*以毫秒为单位计算rtt*/
       /*显示相关信息*/
       printf("%d byte from %s:icmp_seq=%u ttl=%d rtt=%d  ms\n",
               len,inet_ntoa(from.sin_addr),icmpp->icmp_seq,ipp->ip_ttl,rtt);
   }
   else
       return -1;
}
void tv_sub(struct timeval *out,struct timeval *in)
{
   if((out->tv_usec-=in->tv_usec)<0)
   {
       out->tv_sec-=1;
       out->tv_usec+=1000000;
   }
   out->tv_sec-=in->tv_sec;
}
int main(int argc,char **argv)
{
   struct hostent *host;
   struct protoent *protocol;
   int size=50*1024;
   if(argc<2)
   {
       printf("usage : %s hostname/IP address \n",argv[0]);
       exit(1);
   }
   if((protocol=getprotobyname("icmp"))==NULL)
   {
       perror("getprotobyname\n");
       exit(1);
   }
   /*生成使用ICMP的原始套接字,这种套接字只是root才能生成*/
   if((sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto))<0)
   {
       perror("socket error\n");
       exit(1);
   }
   /*回收root权限,设置当前用户权限*/
   setuid(getuid());
   /*扩大套接字接收缓冲区到50K,这样做主要为了减少接收缓冲区溢出的可能性,若无意中ping一个广播地址或多播地址,将会引来大量应答*/
   setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size));
   bzero(&dest_addr,sizeof(dest_addr));
   dest_addr.sin_family=AF_INET;
   if((host=gethostbyname(argv[1]))==NULL)
   {
       perror("gethostbyname error\n");
       exit(1);
   }
   dest_addr.sin_addr=*((struct in_addr *)host->h_addr);
   pid=getpid();
   printf("PING %s(%s): %d bytes data in ICMP packets.\n",argv[1],inet_ntoa(dest_addr.sin_addr),datalen);
   send_packet();/*发送所有ICMP报文*/
   recv_packet();/*接收所有ICMP报文*/
   statistics(SIGALRM);/*进行统计*/

   return 0;
}

本文出自 “好好活着” 博客,请务必保留此出处http://wolfword.blog.51cto.com/4892126/1225685

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索int
, struct
, include
, 字节
, timeval
, unsigned
累加和校验算法
c语言实现ping命令、多线程ping命令的实现、java实现ping命令、ping命令的c语言实现、ping命令实现,以便于您获取更多的相关知识。

时间: 2025-01-07 12:35:29

实现ping命令的代码的相关文章

ASP调用系统ping命令

使用WSH调用系统的Ping命令,将Ping的结果重定向到一个文本文件中去,再把文本文件显示到网页中 具体做法如下: 首先, 建一个.BAT文件(例如:myPing.BAT:),这个文件要在ASP中调用,文件代码如下: ping -a %1 > d:\INetPub\cgi-bin\%2.txt (%1)是将来要ping的地址, (%2)是存储ping结果的文件. 以下是ASP的代码: < % Set FileSys = Server.CreateObject("Scripting.

在ASP中执行Ping命令,并且返回结果

执行 在ASP中执行Ping命令,并且返回结果 在Win2000系统中,可以通过Wscript.Shell对象的Exec方法执行命令, 简单的代码如下: <% Response.Buffer = true %> <% url = "www.topronet.com" Set objWShell = CreateObject("WScript.Shell") Set objCmd = objWShell.Exec("ping "

使用C#调用外部Ping命令获取网络连接情况

网络 以前在玩Windows 98的时候,几台电脑连起来,需要测试网络连接是否正常,经常用的一个命令就是Ping.exe.感觉相当实用. 现在 .net为我们提供了强大的功能来调用外部工具,并通过重定向输入.输出获取执行结果,下面就用一个例子来说明调用Ping.exe命令实现网络的检测,希望对.net初学者有所帮助. 首先,我们用使用Process类,来创建独立的进程,导入System.Diagnostics, using System.Diagnostics; 实例一个Process类,启动一

ping命令的使用

  ping命令的工作原理: ping的原理就是首先建立通道,然后发送包,对方接受后返回信息,这个包至少包括以下内容,发送的时候,包的内容包括对方的ip地址和自己的地址,还有序列数,回送的时候包括双方地址,还有时间等,主要是接受方在都是在操作系统内核里做好的,时刻在监听,提供一段c程序的代码.网络上的机器都有唯一确定的IP地址,我们给目标IP地址发送一个数据包,对方就要返回一个同样大小的数据包,根据返回的数据包我们可以确定目标主机的存在,可以初步判断目标主机的操作系统等. 比如你来ping一下网

socket编程 ping命令-socket编程——内网ping公网失败

问题描述 socket编程--内网ping公网失败 我电脑连的是铁通的公网,在做一个C/S socket编程.在我一台电脑上客户端和服务器之间可以正常发送数据,但是客户端放到别的可以上网的电脑上时就连不上了.我用ping命令检测过网络情况,基本上都ping不通.只有一次一个同学在公司用他的电脑ping通了,不过是单向的,我还是Ping不通他的,服务器和客户端之间还是发送不了数据.有哪位高手知道是什么原因?谢谢! 服务器端部分代码如下: //设定地址 serv.sin_addr.s_addr=ht

linux-Android在主线程里用handler循环ping命令固定次数会出现ioexception

问题描述 Android在主线程里用handler循环ping命令固定次数会出现ioexception 我做了一个ping百度的程序,使用的是handler循环.下面是循环体: private Handler handler = new Handler(); private Runnable task = new Runnable() { public void run() { // TODO Auto-generated method stub handler.postDelayed(this

教你使用Ping命令排除网络故障

Ping命令简介在我们的网络诊断测试过程中,Ping是个使用频率极高的实用程序,用于确定本地主机是否能与另一台主机交换(发送与接收)数据包.根据返回的信息,我们就可以推断TCP/IP参数是否设置得正确以及运行是否正常.需要注意的是:成功地与另一台主机进行一次或两次数据包的交换并不表示TCP/IP配置就是正确的,我们必须执行大量的本地主机与 远程主机的数据包交换,才能确信TCP/IP的正确性.简单的说,Ping就是一个测试程序,如果Ping运行正确,我们大体上就可以排除 网络访问层.网卡.MODE

php模拟ping命令(php exec函数的使用方法)_php实例

使用php模拟我们常用的DOS命令ping命令的方法,这里主要用到的是php的内置函数exec来调用系统的ping命令,从而实现ping命令功能的. 复制代码 代码如下: <?php$to_ping='www.phpernote.com';$count=2;$psize=66;echo "正在执行php ping命令,请等待...\n<br><br>";flush();while(1){ echo "<pre>"; exec

如何使用Ping命令来判断网络故障?

  如何使用Ping命令来判断网络故障: 除了日常生活之外,现时很多企业也离不开网络,比如说电子邮件的业务交往,网络电话VOIP和即时聊天软件的应用,VPN异地信息的交流等也为企业提高的工作效率及节省很大部分的费用. 因此,这种种的应用已经给人们一种依赖性.试问,如果当您的电脑不能上网,估计您连电脑都懒得开了.那么,当电脑不能上网时,我们如何才能准确地判断网络故障出在哪里?又如何能快捷地解决这故障?IT百科教你如何使用ping命令来判断网络故障. 方法/步骤 其实,电脑不能上网大致可分以下几个原