se1012 @ ubuntu: ~ / Desktop / ping $. / myping www.sina.com
PING www.sina.com (202.108.33.60): 56 bytes of data.
------------------- PING statistics ----------------
3 packets transmitted, 0 received, 100% lost, time 0 ms
rtt min / avg / max / mdev = 0.000/-nan/0.000/-nan ms
less likely to use Linux with gdb looked at
(gdb) set args www.sina.com
(gdb) b 129
Breakpoint 1 at 0x8048b10: file ping.c, line 129.
(gdb) r
Starting program: / home/se1012/Desktop/ping/myping www.sina.com
PING www.sina.com (202.108.33.60): 56 bytes of data.
s
Breakpoint 1, recv_packet () at ping.c: 133
133 fromlen = sizeof (from);
(gdb) s
134 signal (SIGALRM, statistics);
(gdb) s
136 while (nreceived
(gdb) s
138 alarm (MAX_WAIT_TIME);
(gdb) s
141 if ((n = recvfrom (sockfd, recvpacket, sizeof (recvpacket), 0, (struct sockaddr *) & ; from, & fromlen)) <0)
(gdb) s
------------------- PING statistics ----------------
3 packets transmitted, 0 received, 100% lost, time 0 ms
rtt min / avg / max / mdev = 0.000/-nan/0.000/-nan ms
[Inferior 1 (process 14069) exited with code 01]
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
at the time of exit of the recvfrom do not know why but also exit1
online with other people's code than the ratio seems to be no difference ah
my code:
#include <stdio.h>
#include <stdlib.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 <netinet/ip_icmp.h>
#include <netdb.h>
#include <setjmp.h>
#include <errno.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; //发送、接收包的数量
double temp_rtt[MAX_NO_PACKETS]; //记录每组收发包的往返时间
double all_time = 0,min = 0,max = 0,avg = 0,mdev = 0;
struct sockaddr_in dest_addr;
struct sockaddr_in from;
struct timeval tvrecv;
pid_t pid; //表示进程id
void statistics(int signo);
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_chksum(unsigned short *addr, int len);
void computer_rtt() //计算rtt最小、大值,平均值,平均差
{
double sum_avg = 0;
int i;
min = max = temp_rtt[0];
avg = all_time/nreceived; //平均值
for(i=0; i<nreceived; 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 signo) //统计数据函数
{
computer_rtt();
printf("\n-------------------PING statistics----------------\n");
printf("%d packets transmitted,%d received,%d%% lost,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; //ICMP头的长度
int sum = 0;
unsigned short *w=addr; //指向ICMP头的指针
unsigned short answer=0;
while(nleft>1) //把ICMP报头二进制数据以2字节为单位累加起来
{
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的高16位和低16位相加
sum += (sum >> 16); //把进位的值也加到校验和上
answer = ~sum; //取反得到校验和
return answer;
}
int pack(int pack_no) //设置ICMP报头
{
int i,packsize;
struct icmp *icmp;
//struct timeval *tval;
icmp = (struct icmp*)sendpacket; //将sendpacket强制转换成ICMP格式
icmp->icmp_type = ICMP_ECHO; //ICMP_ECHO类型的类型号为0
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_seq = pack_no; //ICMP报文的发送顺序
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;
}
//发送3个ICMP报文
void send_packet()
{
int packetsize;
while(nsend < MAX_NO_PACKETS)////while or if?/////
{
nsend++;
packetsize = pack(nsend); //设置ICMP报头
//发送数据报
/*int sendto ( socket s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen ) ;*/
if(sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0)
{
perror("sendto error");
continue;
}
sleep(1); //每隔一秒发送一个ICMP报文
}
}
void recv_packet() //接受所有ICMP报文
{
int n,fromlen;
extern int error;
fromlen = sizeof(from);
signal(SIGALRM,statistics);
while(nreceived < nsend)
{
alarm(MAX_WAIT_TIME);
//接收数据报
/*int recvfrom( SOCKET s, char FAR* buf, int len, int flags,struct sockaddr FAR* from, int FAR* fromlen);*/
if((n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen)) < 0)
{
perror("recvfrom error");
continue;
}
gettimeofday(&tvrecv,NULL); //记录接收时间
if(unpack(recvpacket,n)==-1) //剥去ICMP报头
{
printf("unpack() is wrong\n");
continue;
}
nreceived++;
}
}
int unpack(char *buf,int len) //剥去ICMP报头
{
int i,iphdrlen; //ip头长度
struct ip *ip;
struct icmp *icmp;
struct timeval *tvsend;
double rtt; //计算往返时延
ip = (struct ip *)buf;
/*求IP报文头长度(ip_hl标识IP头部长度以4字节为单位),即IP报头长度乘4*/
iphdrlen = ip->ip_hl << 2;
icmp = (struct icmp *)(buf + iphdrlen); //越过IP头,指向ICMP报头
len -= iphdrlen; //ICMP报头及ICMP数据报的总长度
if(len < 8) //ICMP报文至少8个字节
{
printf("ICMP packet\'s length is less than 8\n");
return -1;
}
/*判断ICMP报文的类型是否为ICMP_ECHOREPLY并且为本进程的PID(确保所接收的是自己所发的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; //总时间
//显示相关的信息
/*char *inet_ntoa (struct in_addr); 将网络地址转换成"."点隔的字符串格式*/
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);
return 0;
}
else{
printf("ICMP packet is not ECHOREPLY or PID is not right\n");
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{ //接受时间usec小于发送时间usec
recvtime->tv_sec = sec - 1;
recvtime->tv_usec =1000000+usec;
}
}
int main(int argc,char *argv[]) //主函数
{
struct hostent *host=NULL; //host entry,记录主机信息
struct protoent *protocol=NULL; //
unsigned long inaddr = 0;
int waittime = MAX_WAIT_TIME;
int size = 50 * 1024;
//参数小于两个
if(argc < 2)
{
printf("usage:%s hostname/IP address\n",argv[0]);
exit(1);
}
//不是ICMP协议
/*struct protoent * getprotobyname( const char *name ); 返回对应于给定协议名的包含名字和协议号的protoent结构指针*/
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权限,设置当前用户权限
/*uid_t getuid(void);返回一个调用程序的真实用户ID
int setuid(uid_t uid);设置实际用户ID和有效用户ID*/
setuid(getuid());
/*扩大套接字的接收缓存区到50K,这样做是为了减小接收缓存区溢出的可能性,若无意中ping一个广播地址或多播地址,将会引来大量的应答.
int setsockopt(SOCKET s,int level,int optname,const char* optval,int optlen);*/
setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size));
//初始化dest_addr
/*void *memset(void *s, int ch, size_t n);将s中前n个字节 (typedef unsigned int size_t)用 ch 替换并返回 s */
memset(&dest_addr,0,sizeof(dest_addr));
dest_addr.sin_family = AF_INET; //设置协议家族类型为AF_INET
//判断第二个参数是否为主机名或IP地址
/*in_addr_t inet_addr(const char *cp); 将一个点分十进制的IP转换成一个长整数型.正确执行将返回一个无符号长整数型数。如果传入的字符串不是一个合法的IP地址,将返回INADDR_NONE*/
if(inaddr=inet_addr(argv[1]) == INADDR_NONE) //不是合法IP地址
{
/*通过DNS取得IP地址.gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针.若错误返回一个空指针*/
if((host = gethostbyname(argv[1])) == NULL) //不是合法主机名
{
perror("gethostbyname error");
exit(1);
}
/*void *memcpy(void *dest, const void *src, size_t n);从src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中*/
memcpy((char *)&dest_addr.sin_addr,host->h_addr,host->h_length);
}
else{ //是IP地址
dest_addr.sin_addr.s_addr = inaddr; /*or memcpy((char *)&dest_addr.sin_addr,argv[1],strlen(argv[1])+1);*/
}
//获取main的进程id,用于设置ICMP的标志符
pid = getpid();
printf("PING %s(%s):%d bytes of data.\n",argv[1],inet_ntoa(dest_addr.sin_addr),datalen);
send_packet(); /*发送所有ICMP报文*/
recv_packet(); /*接收所有ICMP报文*/
statistics(SIGALRM); /*进行统计*/
return 0;
}
------ Solution ------------------------------------- -------
main function inside if (inaddr = inet_addr (argv [1]) == INADDR_NONE)
if ((inaddr = inet_addr (argv [1])) == INADDR_NONE)
------ Solution --------------- -----------------------------
virtual machine settings that must be the problem
------ For reference only ---------------------------------------
Manga. . .
it is mainly a problem here
void recv_packet() //接受所有ICMP报文
{
int n,fromlen;
extern int error;
fromlen = sizeof(from);
signal(SIGALRM,statistics);
while(nreceived < nsend)
{
alarm(MAX_WAIT_TIME);
//接收数据报
/*int recvfrom( SOCKET s, char FAR* buf, int len, int flags,struct sockaddr FAR* from, int FAR* fromlen);*/
if((n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen)) < 0)
{
perror("recvfrom error");
continue;
}
gettimeofday(&tvrecv,NULL); //记录接收时间
if(unpack(recvpacket,n)==-1) //剥去ICMP报头
{
printf("unpack() is wrong\n");
continue;
}
nreceived++;
}
}
------ For reference only ----------------------------------- ----
very grateful to point out my mistake but the results have not changed ah
I gdb trace is to recv_packet () in
if ((n = recvfrom (sockfd, recvpacket, sizeof (recvpacket), 0, (struct sockaddr *) & from, & fromlen)) <0)
when he withdrew not know why ah
(gdb) s
141 if ((n = recvfrom (sockfd, recvpacket, sizeof (recvpacket), 0, (struct sockaddr *) & ; from, & fromlen)) <0)
(gdb) s
------------------- PING statistics ----------------
3 packets transmitted, 0 received, 100% lost, time 0 ms
rtt min / avg / max / mdev = 0.000/-nan/0.000/-nan ms
[Inferior 1 (process 14069) exited with code 01]
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
------ For reference only ---------------------------------- -----
your code line that changed the result of error, I tried it is possible ah.
ping about the system you are using, and then try to switch the root user
#. / testping www.sina.com
PING www.sina.com (61.172.201.194): 56 bytes of data.
64 bytes from 61.172.201.194: icmp_seq = 1 ttl = 244 time = 1465899937.0 ms
64 bytes from 61.172.201.194: icmp_seq = 2 ttl = 244 time = 1465899937.0 ms
64 bytes from 61.172.201.194: icmp_seq = 3 ttl = 244 time = 1465899937.0 ms
------------------- PING statistics ----------------
3 packets transmitted, 3 received, 0% lost, time 4397699811 ms
rtt min / avg / max / mdev = 1465899937.000/1465899937.000/1465899937.000/0.000 ms
------ For reference only ----------- ----------------------------
Well I system will not ping. . . I have a linux virtual machine network with a NAT Why not ping ah. . .
se1012 @ ubuntu: ~ / Desktop / ping $ ping www.sina.com.cn
PING polaris.sina.com.cn (202.108.33.60) 56 (84) bytes of data.
^ C
--- polaris.sina.com.cn ping statistics ---
13 packets transmitted, 0 received, 100% packet loss, time 12084ms
------ For reference only ---------------------------------- -----
yes. . . I Baidu half did not solve
DNS on the external network can also resolve the ping is not coming back
I set IP addresses and NAT gateways and VMnet8 are matched to solve ah depressed dead
------ For reference only ---------------------------------- -----
use bridges to try