2013年8月31日星期六

Q: linux under ping lost 100% could not find a reason for worry!

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

没有评论:

发表评论