Каков наилучший способ пинговать в C ++ под Linux? - PullRequest
6 голосов
/ 24 ноября 2008

Мне нужно вызвать ping из кода C ++. Я хотел бы легко прочитать вывод для дальнейшего использования.

Я предложил два решения:

  • используйте вилку и канал, перенаправьте вывод ping на канал и затем проанализируйте его
  • найти библиотеку, подходящую для прямого использования функции ping (ip_addresss)

Мне бы хотелось последнее, но я не нашел ничего, что было бы стандартным решением.

Как бы вы это сделали?

Ответы [ 6 ]

9 голосов
/ 24 ноября 2008

С образовательной точки зрения использование внешнего двоичного файла очень нецелесообразно . Специально для такой простой задачи, как отправка эхо-запроса ICMP, вам следует изучить немного сокетов.

7 голосов
/ 22 марта 2013
#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 голосов
/ 24 ноября 2008

Я бы пошел с вашим первым вариантом. Linux построен на концепции небольших специализированных приложений, которые действительно хорошо выполняют свою работу, общаясь с помощью каналов. Ваше приложение не должно включать библиотеку для реализации ping, поскольку для этого уже есть встроенная команда, и она работает очень хорошо!

2 голосов
/ 24 ноября 2008

Проверьте источник BusyBox для 'ping' - вы можете использовать функции ping4 и ping6. Просто помните о GPL.

Порождение 'ping' также должно работать - проверьте popen(2) для более простого API, который также запускает оболочку. Если это проблема, pipe + fork + exec должно работать.

2 голосов
/ 24 ноября 2008

Вы можете попробовать использовать этот код .

0 голосов
/ 03 декабря 2008

Мне удалось сделать так:

Я использую popen, который в основном создает pipe, fork и exec Тогда, если мне нужно, я могу подождать с pclose.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...