码迷,mamicode.com
首页 > 其他好文 > 详细

ping

时间:2015-02-21 23:23:14      阅读:295      评论:0      收藏:0      [点我收藏+]

标签:

ping是怎么实现的?它依赖的是原始套接字与ICMP(Internet Control Message Protocol,网际控制消息协议),向目标主机投递回射请求,而目标主机将响应一个回射应答。通常在请求体中包含时间戳,用来计算RTT(Round-trip Time,回环时间),也就是玩家常说的服务器延迟了。

int
main(int argc, char **argv)
{
    int c;
    struct addrinfo *ai;
    char *h;

    opterr = 0;
    while((c = getopt(argc, argv, "v")) != -1)
    {
        switch(c)
        {
        case ‘v‘:
            verbose++;
            break;

        case ‘?‘:
            printf("unrecognized option: %c\n", c);
            return -1;
        }
    }

    if(optind != argc-1)
    {
        printf("usage: ping [-v] <hostname>\n");
        return -1;
    }
    host = argv[optind];

    pid = getpid() & 0xffff;
    signal(SIGALRM, sig_alrm);

    ai = host_serv(host, NULL, 0, 0);

    h = sock_ntop_host(ai->ai_addr, ai->ai_addrlen);
    printf("PING %s (%s): %d data bytes\n",
        ai->ai_canonname ? ai->ai_canonname : h, h, datalen);

    if(ai->ai_family == AF_INET)
    {
        pr = &proto_v4;
    }
    else
    {
        printf("cannot ping IPv4-mapped IPv6 address\n");
        return -1;
    }
    pr->sasend = ai->ai_addr;
    pr->sarecv = (sockaddr*)calloc(1, ai->ai_addrlen);
    pr->salen = ai->ai_addrlen;

    readloop();
}

 

void
readloop()
{
    int size;
    char recvbuf[BUFSIZE];
    char controlbuf[BUFSIZE];
    struct msghdr msg;
    struct iovec iov;
    ssize_t n;
    struct timeval tval;

    sockfd = socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto);
    setuid(getuid());
    if(pr->finit)
        (*pr->finit)();

    size = 60 * 1024;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

    sig_alrm(SIGALRM); // 发送部分,下面先分析此部分

    iov.iov_base = recvbuf;
    iov.iov_len = sizeof(recvbuf);
    msg.msg_name = pr->sarecv;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = controlbuf;
    for(;;)
    {
        msg.msg_namelen = pr->salen;
        msg.msg_controllen = sizeof(controlbuf);
        n = recvmsg(sockfd, &msg, 0);
        if(n < 0)
        {
            if(errno == EINTR)
                continue;
            else
            {
                printf("recvmsg error\n");
                exit(-1);
            }
        }
        gettimeofday(&tval, NULL);
        (*pr->fproc)(recvbuf, n, &msg, &tval); // 接受部分
    }
}

 

void
sig_alrm(int signo)
{
    (*pr->fsend)(); // 构造一个ICMP回射请求
    alarm(1); // 定时发包
}

 

void
send_v4()
{
    int len;
    struct icmp *icmp;

    icmp = (struct icmp*)sendbuf;
    icmp->icmp_type = ICMP_ECHO;
    icmp->icmp_code = 0;
    icmp->icmp_id = pid;
    icmp->icmp_seq = nsent++;
    memset(icmp->icmp_data, 0xa5, datalen);
    gettimeofday((struct timeval*)icmp->icmp_data, NULL);
    
    len = 8 + datalen;
    icmp->icmp_cksum = 0;
    icmp->icmp_cksum = in_cksum((u_short*)icmp, len);

    sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen); // 虽然是原始套接字,但IP头由OS添加
}

 

void
proc_v4(char *ptr, ssize_t len, struct msghdr *msg, struct timeval *tvrecv)
{
    int hlenl, icmplen;
    double rtt;
    struct ip *ip;
    struct icmp *icmp;
    struct timeval *tvsend;

    ip = (struct ip*)ptr; // 但接受到的则是整个IP包了,要自己提取ICMP部分
    hlenl = ip->ip_hl << 2;
    if(ip->ip_p != IPPROTO_ICMP)
        return;
    
    icmp = (struct icmp*)(ptr + hlenl);
    if((icmplen = len - hlenl) < 8)
        return;

    if(icmp->icmp_type == ICMP_ECHOREPLY)
    {
        if(icmp->icmp_id != pid)
            return;
        if(icmplen < 16)
            return;
        tvsend = (struct timeval*)icmp->icmp_data;
        tv_sub(tvrecv, tvsend);
        rtt = tvrecv->tv_sec * 1000.0 + tvrecv->tv_usec / 1000.0;

        printf("%d bytes from %s: seq=%u, ttl=%d, rtt=%.3f ms\n",
            icmplen, sock_ntop_host(pr->sarecv, pr->salen), icmp->icmp_seq, ip->ip_ttl, rtt);

    }
    else if(verbose)
    {
        printf("%d bytes from %s: type=%d, code=%d\n",
            icmplen, sock_ntop_host(pr->sarecv, pr->salen), icmp->icmp_type, icmp->icmp_code);
    }
}

ping

标签:

原文地址:http://www.cnblogs.com/mynamepfd/p/4297204.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!