17 12
发新话题
打印

自己写了个ping 可是不知为什么收不到第一个包的回复

自己写了个ping 可是不知为什么收不到第一个包的回复

复制内容到剪贴板
代码:
# include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <errno.h>
#include <netinet/ip_icmp.h>

# define PACKSIZE 1024
char p_send[PACKSIZE];
char p_recv[PACKSIZE];
struct timeval *s_time,r_time;
pid_t pid;
struct sockaddr_in server_addr,source_addr;
int sockfd;
int nsend=1,nreceived=0;

void re_output(int signo);
unsigned short checksum(unsigned short *,int);
int p_pack(int );
void send_pack();
void recv_pack();
void unpack(char*,int );
void usedtime(struct timeval *,struct timeval *);
void p_socket();


void p_socket()
{
    int  n;
    int size = 1024*50;
    n=setuid(getuid());  //提升权限,好像没起作用,所以需要root用户
    printf("%d\n",n);
    struct protoent *proto;
    if ((proto=getprotobyname("icmp"))==NULL)
    {
        printf("your enveriment wrong\n");
        exit(1);
    }
   
    server_addr.sin_family = AF_INET;
    bzero(&(server_addr.sin_zero), 8);
    server_addr.sin_addr.s_addr=inet_addr("192.168.0.214");
    //source_addr.sin_addr.s_addr=inet_addr("192.168.0.200");   
    if((sockfd=socket(AF_INET,SOCK_RAW,proto->p_proto))==-1)
    {
        fprintf(stderr,"socket error:%s\n",strerror(errno));
        printf("creat a socket error\n");
        exit(1);
    }
        setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size) );  //set socket option  扩大缓冲区,防止益出

}

void re_output(int signo)         //can shu que shao   打印输出,遇到中断就打印ctrl+c,还没调好
{
    printf("%dpack sent,%dreceved, %d%%lost\n",nsend,nreceived,(nsend-nreceived)/nsend*100);
    close(sockfd);
    exit(1);
}

unsigned short checksum(unsigned short *addr,int len)   //校验和
{
    unsigned short *paddr=addr;
    unsigned short fillbyte=0;
    int sum, nleft=len;

    while(nleft>1)
    {
        sum+=*paddr++;
        nleft-=2;
    }
   
    if(nleft=1)
    {
        *(unsigned char *)(&fillbyte)=*(unsigned char *)paddr;
        sum+=fillbyte;
    }
    sum=(sum>>16)+(sum&0xffff);
    sum+=(sum>>16);
    fillbyte=~sum;
    return fillbyte;
}
        


int
p_pack(int seq)
{
    struct icmp *icmp;
    struct timeval *tval;
    int datalen=56,pack_size;
   
    icmp=(struct icmp*)p_send;
    icmp->icmp_type=ICMP_ECHO;
    icmp->icmp_code=0;
    icmp->icmp_cksum=0;
    icmp->icmp_seq=seq;
    icmp->icmp_id=pid;                       //a check number,need to init
   
    pack_size=8+datalen;
    tval=(struct timeval *)icmp->icmp_data;
    gettimeofday(tval,NULL);
    //icmp->icmp_cksum=checksum(icmp,pack_size);   // if else
    icmp->icmp_cksum=checksum((unsigned short *)icmp,pack_size);
    return pack_size;
}


void send_pack()
{
    int packsize,back;
    while(nsend<3)   // send 2  packets
    {
        packsize=p_pack(nsend);
        back=sendto(sockfd,p_send,packsize,0,(struct sockaddr*)&server_addr,sizeof(struct sockaddr_in));
        if(back==-1)
        {
            fprintf(stderr,"send error:%s\n",strerror(errno));
            close(sockfd);
            return;
        }
        ++nsend;
        sleep(1);
    }
}


void recv_pack()
{
    int d_len,nback;
    d_len=sizeof(source_addr);
    signal(SIGALRM,re_output);
    while(nreceived<=nsend)  //小于等于发送个数
    {
        //select();
        
        nback=recvfrom(sockfd,p_recv,PACKSIZE,0,(struct sockaddr*)&source_addr,&d_len);
        printf("nback=%d\n",nback);
        if(nback==-1)   //inter of the computer;
        {
            printf("receive error\n");
            continue;
        }
        gettimeofday(&r_time,NULL);     //计下接收时间
        unpack(p_recv,nback);
        nreceived++;
        
    }
}

void  unpack(char *buff,int n)    //拆包
{
    int len=n;
    struct ip *ip;
    struct icmp *icmp;
    int i,iphdrlen;
    ip=(struct ip*)buff;
    iphdrlen=ip->ip_hl<<2;    //就是ip头的长度
    icmp=(struct icmp*)(buff+iphdrlen);
    len-=iphdrlen;
    if(len<8)
    {
        printf("icmp pack length less than 8\n");
        exit(1);
    }
    if((icmp->icmp_type==ICMP_ECHOREPLY)&&(icmp->icmp_id==pid))
    s_time=(struct timeval*)icmp->icmp_data;
   
    usedtime(&r_time,s_time);
    printf("%d byte from %s: icmp_seq=%u ttl=%d \n",len,inet_ntoa(source_addr.sin_addr),icmp->icmp_seq,ip->ip_ttl);
        

}

void usedtime(struct timeval *t_recv,struct timeval *t_send)   //计算发送和接收时间差
{
       if(t_recv->tv_usec-=t_send->tv_usec<0)
       {
               --t_recv->tv_sec;
           t_recv->tv_usec+=1000000;
       }
       t_recv->tv_sec-=t_send->tv_sec;
}

int
main(int argc, char **argv)
{
    pid=getpid();
    p_socket();
    send_pack();
    recv_pack();
    re_output(SIGALRM);
    return(1);
   
}
      

TOP

tcpdump时候发现第一个包发出去了,可就是没有第一个包的回复,正常情况应该是发一个request回复一个,可是抓包时,前两个都是request,第三个是回复第二个请求的。请高手指点一下,小弟刚开始看网络编成。      

TOP

很可能是组包错误,被对方丢弃了。      
上帝说,有问题,找GOOGLE 写程序是很神圣的事情!同样只是装系统,卖菜的大娘会的事情不见得就跟卖菜一样了。

TOP

组包错误?那以后发的包也应该被丢弃阿,为什么只丢弃了第一个,会不会有缓存清空的问题?      

TOP

试了一下,运行Segmentation fault。。。。。。
& [/ `# N: G) l开始没做测试,不过现在测试用ethereal抓包是显示第一个包的checksum错了。      
上帝说,有问题,找GOOGLE 写程序是很神圣的事情!同样只是装系统,卖菜的大娘会的事情不见得就跟卖菜一样了。

TOP

试了一下
) H" X  J7 @/ ^3 ?3 q( [8 k  `6 B开始没做测试,不过现在测试用ethereal抓包是显示第一个包的checksum错了。      
上帝说,有问题,找GOOGLE 写程序是很神圣的事情!同样只是装系统,卖菜的大娘会的事情不见得就跟卖菜一样了。

TOP

哦,谢谢版主了,我能体会当到版主的不容易了。 谢谢。
5 A4 f5 M- i: E, L$ k+ \" R我再找一下问题所在,还有再问一下,我感觉这样写ping好像不是很合适,无论用微软的ping还是linux里面的ping都没有等待发包的时间,至少我没有感觉到,可是自己写的明显能感觉到等待发包的的时间,所有的包发送完了后才开始显示接受的信息。难道需要改成send完了就recv?好像更不合适,要不就其两个线程,一个负责发,一个负责接?大家给个意见吧。      

TOP

不明白你说的等待是什么意思?你是说接受的时候有时延所以等了还是什么意思?
2 `6 b1 {/ T( K不过仅仅是个ping也要用两个线程没有任何必要吧?      
上帝说,有问题,找GOOGLE 写程序是很神圣的事情!同样只是装系统,卖菜的大娘会的事情不见得就跟卖菜一样了。

TOP

版主说的有道理,第一个包收不到恢复的那个问题搞定了,只需要清一下发送缓存就可以了,memset一下就可以了。还有,我说的那个等待就是,要等到所有的包发送完了后,才开始接收 返回包,比如我要发100个包,那意味着我要等100秒后才能收包,不知到linux上是怎么实现的。      

TOP

为什么要发完所有的才接收?      
上帝说,有问题,找GOOGLE 写程序是很神圣的事情!同样只是装系统,卖菜的大娘会的事情不见得就跟卖菜一样了。

TOP

 17 12
发新话题