【问题标题】:What is the best method to ping in c++ under linux?在linux下用c ++ ping的最佳方法是什么?
【发布时间】:2008-11-24 08:59:19
【问题描述】:

我必须从 c++ 代码调用 ping。我想轻松读取输出以供进一步使用。

我想出了两个解决方案:

  • 使用分叉和管道,将 ping 输出重定向到管道,然后解析它
  • 找到适合直接使用 ping(ip_addresss) 函数的库

我想要后者,但我没有找到任何明显是标准解决方案的东西。

你会怎么做?

【问题讨论】:

    标签: c++ linux


    【解决方案1】:

    从教育的角度来看,调用外部二进制文件非常不可取。特别是对于发送 ICMP 回显请求这样的简单任务,您应该学习一点套接字。

    【讨论】:

    • ICMP 需要 root。见上文。
    【解决方案2】:
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/socket.h>
    #include <resolv.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <netinet/ip_icmp.h>
    
    
    #define PACKETSIZE  64
    struct packet
    {
        struct icmphdr hdr;
        char msg[PACKETSIZE-sizeof(struct icmphdr)];
    };
    
    int pid=-1;
    struct protoent *proto=NULL;
    int cnt=1;
    
    /*--------------------------------------------------------------------*/
    /*--- checksum - standard 1s complement checksum                   ---*/
    /*--------------------------------------------------------------------*/
    unsigned short checksum(void *b, int len)
    {
        unsigned short *buf = b;
        unsigned int sum=0;
        unsigned short result;
    
        for ( sum = 0; len > 1; len -= 2 )
            sum += *buf++;
        if ( len == 1 )
            sum += *(unsigned char*)buf;
        sum = (sum >> 16) + (sum & 0xFFFF);
        sum += (sum >> 16);
        result = ~sum;
        return result;
    }
    
    
    /*--------------------------------------------------------------------*/
    /*--- ping - Create message and send it.                           ---*/
    /*    return 0 is ping Ok, return 1 is ping not OK.                ---*/
    /*--------------------------------------------------------------------*/
    int ping(char *adress)
    {
        const int val=255;
        int i, sd;
        struct packet pckt;
        struct sockaddr_in r_addr;
        int loop;
        struct hostent *hname;
        struct sockaddr_in addr_ping,*addr;
    
        pid = getpid();
        proto = getprotobyname("ICMP");
        hname = gethostbyname(adress);
        bzero(&addr_ping, sizeof(addr_ping));
        addr_ping.sin_family = hname->h_addrtype;
        addr_ping.sin_port = 0;
        addr_ping.sin_addr.s_addr = *(long*)hname->h_addr;
    
        addr = &addr_ping;
    
        sd = socket(PF_INET, SOCK_RAW, proto->p_proto);
        if ( sd < 0 )
        {
            perror("socket");
            return 1;
        }
        if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0)
        {
            perror("Set TTL option");
            return 1;
        }
        if ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 )
        {
            perror("Request nonblocking I/O");
            return 1;
        }
    
        for (loop=0;loop < 10; loop++)
        {
    
            int len=sizeof(r_addr);
    
            if ( recvfrom(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&r_addr, &len) > 0 )
            {
                return 0;
            }
    
            bzero(&pckt, sizeof(pckt));
            pckt.hdr.type = ICMP_ECHO;
            pckt.hdr.un.echo.id = pid;
            for ( i = 0; i < sizeof(pckt.msg)-1; i++ )
                pckt.msg[i] = i+'0';
            pckt.msg[i] = 0;
            pckt.hdr.un.echo.sequence = cnt++;
            pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));
            if ( sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 )
                perror("sendto");
    
            usleep(300000);
    
        }
    
        return 1;
    }
    
    /*--------------------------------------------------------------------*/
    /*--- main - look up host and start ping processes.                ---*/
    /*--------------------------------------------------------------------*/
    int main(int argc, char *argv[])
    {
    
        if (ping("www.google.com"))
            printf("Ping is not OK. \n");
        else
            printf("Ping is OK. \n");
    
    
        return 0;
    }
    

    【讨论】:

    【解决方案3】:

    我会选择你的第一个选项。 Linux 是围绕着这样一个概念构建的,即拥有小型、专门的应用程序,这些应用程序可以很好地完成一件事,即与管道通信。您的应用不应包含实现 ping 的库,因为已经有一个内置命令可以执行此操作,而且效果很好!

    【讨论】:

    • 是的,第一个解决方案似乎是最好的方法。同样使用 ICMP 协议需要 root 权限。
    【解决方案4】:

    查看 BusyBox 的 source for 'ping' - 您可以使用 ping4ping6 函数。请注意 GPL。

    生成 'ping' 也应该可以工作 - 查看popen(2) 以获得更简单的 API,该 API 也可以运行 shell。如果有问题,pipe + fork + exec 应该可以工作。

    【讨论】:

    【解决方案5】:

    我已经做到了:

    我使用 popen,它基本上创建了一个管道、fork 和 exec 然后,如果我需要,我可以用 pclose 等待。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-31
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      • 2018-08-21
      相关资源
      最近更新 更多