问:linux下实现ping lost 100% 没找到原因 急!

黄大仙儿 2013-08-06 08:06:11
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


不太会用Linux 用gdb看了一下

(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 < nsend)
(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

在recvfrom的时候直接退出了 不知道为什么 而且还是exit1
跟网上别人的代码比了比 好像没什么区别啊

我的代码:

#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;
}
...全文
1419 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
黄大仙儿 2014-03-20
  • 打赏
  • 举报
回复
引用 9 楼 qq907240636 的回复:
请问下 这个问题最后怎么解决的 我也遇到了这个问题
后来发现VMNET8的IP地址莫名其妙的变了。。。后来又重新配了一下就没问题了 看你NAT设置的IP地址和网关和VMnet8是不是匹配的
qq907240636 2014-03-20
  • 打赏
  • 举报
回复
请问下 这个问题最后怎么解决的 我也遇到了这个问题
falloutmx 2013-08-09
  • 打赏
  • 举报
回复
改用桥接的方式试试
falloutmx 2013-08-08
  • 打赏
  • 举报
回复
那必然是虚拟机设置的问题了
黄大仙儿 2013-08-08
  • 打赏
  • 举报
回复
是。。。我百度半天也没解决 可以上外网 DNS也能解析出 就是ping不回来 我NAT设置的IP地址和网关和VMnet8是匹配的 求解啊 郁闷死了
引用 6 楼 falloutmx 的回复:
那必然是虚拟机设置的问题了
黄大仙儿 2013-08-07
  • 打赏
  • 举报
回复
非常感谢指出我这个错误 但是结果没有变啊 我gdb跟踪是到recv_packet()的 if((n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen)) < 0) 的时候就退出了 不知道原因啊 (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
引用 2 楼 qiyu1988 的回复:
main 函数里面if(inaddr=inet_addr(argv[1]) == INADDR_NONE) if((inaddr=inet_addr(argv[1])) == INADDR_NONE)
qiyu1988 2013-08-07
  • 打赏
  • 举报
回复
main 函数里面if(inaddr=inet_addr(argv[1]) == INADDR_NONE) if((inaddr=inet_addr(argv[1])) == INADDR_NONE)
黄大仙儿 2013-08-07
  • 打赏
  • 举报
回复
帮帮忙啊。。。 主要是这里有问题吧

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++;
    }
}
黄大仙儿 2013-08-07
  • 打赏
  • 举报
回复
好吧 我系统就ping不通。。。我的是linux虚拟机 网络配的NAT 为什么ping不通啊。。。 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
引用 4 楼 qiyu1988 的回复:
你的代码改了那行错误后的结果,我试了下是可以的啊。 你用系统的ping一下,切换root用户再试试 # ./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
qiyu1988 2013-08-07
  • 打赏
  • 举报
回复
你的代码改了那行错误后的结果,我试了下是可以的啊。 你用系统的ping一下,切换root用户再试试 # ./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

18,773

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 专题技术讨论区
社区管理员
  • 专题技术讨论区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧