linux 程序实现 ping,C代码实现Linux下模拟ping命令

下面是编程之家 jb51.cc 通过网络收集整理的代码片段。

编程之家小编现在分享给大家,也给大家做个参考。

/********************************************************

* IP报头格式数据结构定义在中 *

* ICMP数据结构定义在中 *

* 套接字地址数据结构定义在中 *

********************************************************/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PACKET_SIZE 4096

#define MAX_WAIT_TIME 5

#define MAX_NO_PACKETS 10000

char *addr[];

char sendpacket[PACKET_SIZE];

char recvpacket[PACKET_SIZE];

int sockfd,datalen = 56;

int nsend = 0,nreceived = 0;

double temp_rtt[MAX_NO_PACKETS];

double all_time = 0;

double min = 0;

double max = 0;

double avg = 0;

double mdev = 0;

struct sockaddr_in dest_addr;

struct sockaddr_in from;

struct timeval tvrecv;

pid_t pid;

void statistics(int sig);

void send_packet(void);

void recv_packet(void);

void computer_rtt(void);

void tv_sub(struct timeval *out,struct timeval *in);

int pack(int pack_no);

int unpack(char *buf,int len);

unsigned short cal_checksum(unsigned short *addr,int len);

/*计算rtt最小、大值,平均值,算术平均数差*/

void computer_rtt()

{

double sum_avg = 0;

int i;

min = max = temp_rtt[0];

avg = all_time/nreceived;

for(i=0; i

if(temp_rtt[i] < min)

min = temp_rtt[i];

else if(temp_rtt[i] > max)

max = temp_rtt[i];

if((temp_rtt[i]-avg) < 0)

sum_avg += avg - temp_rtt[i];

else

sum_avg += temp_rtt[i] - avg;

}

mdev = sum_avg/nreceived;

}

/****统计数据函数****/

void statistics(int sig)

{

computer_rtt(); //计算rtt

printf("\n------ %s ping statistics ------\n",addr[0]);

printf("%d packets transmitted,%d received,%d%% packet loss,time %.f ms\n",nsend,nreceived,(nsend-nreceived)/nsend*100,all_time);

printf("rtt min/avg/max/mdev = %.3f/%.3f/%.3f/%.3f ms\n",min,avg,max,mdev);

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 check_sum = 0;

while(nleft>1) //ICMP包头以字(2字节)为单位累加

{

sum += *w++;

nleft -= 2;

}

if(nleft == 1) //ICMP为奇数字节时,转换最后一个字节,继续累加

{

*(unsigned char *)(&check_sum) = *(unsigned char *)w;

sum += check_sum;

}

sum = (sum >> 16) + (sum & 0xFFFF);

sum += (sum >> 16);

check_sum = ~sum; //取反得到校验和

return check_sum;

}

/*设置ICMP报头*/

int pack(int pack_no)

{

int i,packsize;

struct icmp *icmp;

struct timeval *tval;

icmp = (struct icmp*)sendpacket;

icmp->icmp_type = ICMP_ECHO; //ICMP_ECHO类型的类型号为0

icmp->icmp_code = 0;

icmp->icmp_cksum = 0;

icmp->icmp_seq = pack_no; //发送的数据报编号

icmp->icmp_id = pid;

packsize = 8 + datalen; //数据报大小为64字节

tval = (struct timeval *)icmp->icmp_data;

gettimeofday(tval,NULL); //记录发送时间

//校验算法

icmp->icmp_cksum = cal_chksum((unsigned short *)icmp,packsize);

return packsize;

}

/****发送三个ICMP报文****/

void send_packet()

{

int packetsize;

if(nsend < MAX_NO_PACKETS)

{

nsend++;

packetsize = pack(nsend); //设置ICMP报头

//发送数据报

if(sendto(sockfd,sendpacket,packetsize,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0)

{

perror("sendto error");

}

}

}

/****接受所有ICMP报文****/

void recv_packet()

{

int n,fromlen;

extern int error;

fromlen = sizeof(from);

if(nreceived < nsend)

{

//接收数据报

if((n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),(struct sockaddr *)&from,&fromlen)) < 0)

{

perror("recvfrom error");

}

gettimeofday(&tvrecv,NULL); //记录接收时间

unpack(recvpacket,n); //剥去ICMP报头

nreceived++;

}

}

/******剥去ICMP报头******/

int unpack(char *buf,int len)

{

int i;

int iphdrlen; //ip头长度

struct ip *ip;

struct icmp *icmp;

struct timeval *tvsend;

double rtt;

ip = (struct ip *)buf;

iphdrlen = ip->ip_hl << 2; //求IP报文头长度,即IP报头长度乘4

icmp = (struct icmp *)(buf + iphdrlen); //越过IP头,指向ICMP报头

len -= iphdrlen; //ICMP报头及数据报的总长度

if(len < 8) //小于ICMP报头的长度则不合理

{

printf("ICMP packet\'s length is less than 8\n");

return -1;

}

//确保所接收的是所发的ICMP的回应

if((icmp->icmp_type == ICMP_ECHOREPLY) && (icmp->icmp_id == pid))

{

tvsend = (struct timeval *)icmp->icmp_data;

tv_sub(&tvrecv,tvsend); //接收和发送的时间差

//以毫秒为单位计算rtt

rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000;

temp_rtt[nreceived] = rtt;

all_time += rtt; //总时间

//显示相关的信息

printf("%d bytes from %s: icmp_seq=%u ttl=%d time=%.1f ms\n",len,inet_ntoa(from.sin_addr),icmp->icmp_seq,ip->ip_ttl,rtt);

}

else return -1;

}

//两个timeval相减

void tv_sub(struct timeval *recvtime,struct timeval *sendtime)

{

long sec = recvtime->tv_sec - sendtime->tv_sec;

long usec = recvtime->tv_usec - sendtime->tv_usec;

if(usec >= 0){

recvtime->tv_sec = sec;

recvtime->tv_usec = usec;

}else{

recvtime->tv_sec = sec - 1;

recvtime->tv_usec = -usec;

}

}

/*主函数*/

main(int argc,char *argv[])

{

struct hostent *host;

struct protoent *protocol;

unsigned long inaddr = 0;

// int waittime = MAX_WAIT_TIME;

int size = 50 * 1024;

addr[0] = argv[1];

//参数小于两个

if(argc < 2)

{

printf("usage:%s hostname/IP address\n",argv[0]);

exit(1);

}

//不是ICMP协议

if((protocol = getprotobyname("icmp")) == NULL)

{

perror("getprotobyname");

exit(1);

}

//生成使用ICMP的原始套接字,只有root才能生成

if((sockfd = socket(AF_INET,SOCK_RAW,protocol->p_proto)) < 0)

{

perror("socket error");

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; //套接字域是AF_INET(网络套接字)

//判断主机名是否是IP地址

if(inet_addr(argv[1]) == INADDR_NONE)

{

if((host = gethostbyname(argv[1])) == NULL) //是主机名

{

perror("gethostbyname error");

exit(1);

}

memcpy((char *)&dest_addr.sin_addr,host->h_addr,host->h_length);

}

else{ //是IP 地址

dest_addr.sin_addr.s_addr = inet_addr(argv[1]);

}

pid = getpid();

printf("PING %s(%s):%d bytes of data.\n",argv[1],inet_ntoa(dest_addr.sin_addr),datalen);

//当按下ctrl+c时发出中断信号,并开始执行统计函数

signal(SIGINT,statistics);

while(nsend < MAX_NO_PACKETS){

sleep(1); //每隔一秒发送一个ICMP报文

send_packet(); //发送ICMP报文

recv_packet(); //接收ICMP报文

}

return 0;

}

/********************************************************

* IP报头格式数据结构定义在中 *

* ICMP数据结构定义在中 *

* 套接字地址数据结构定义在中 *

********************************************************/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PACKET_SIZE 4096

#define MAX_WAIT_TIME 5

#define MAX_NO_PACKETS 10000

char *addr[];

char sendpacket[PACKET_SIZE];

char recvpacket[PACKET_SIZE];

int sockfd,statistics);

while(nsend < MAX_NO_PACKETS){

sleep(1); //每隔一秒发送一个ICMP报文

send_packet(); //发送ICMP报文

recv_packet(); //接收ICMP报文

}

return 0;

}

以上是编程之家(jb51.cc)为你收集整理的全部代码内容,希望文章能够帮你解决所遇到的程序开发问题。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

总结

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值