Функция Ping не работает после 1020 попыток - PullRequest
2 голосов
/ 11 января 2011

У меня есть программа, которая должна постоянно пинговать устройство

Однако эта функция пинга не работает точно после 1020 попыток

int ping(string target)
{

int s, i, cc, packlen, datalen = DEFDATALEN;
struct hostent *hp;
struct sockaddr_in to, from;
//struct protoent   *proto;
struct ip *ip;
u_char *packet, outpack[MAXPACKET];
char hnamebuf[MAXHOSTNAMELEN];
string hostname;
struct icmp *icp;
int ret, fromlen, hlen;
fd_set rfds;
struct timeval tv;
int retval;
struct timeval start, end;
int /*start_t, */end_t;
bool cont = true;

to.sin_family = AF_INET;

// try to convert as dotted decimal address, else if that fails assume it's a hostname
to.sin_addr.s_addr = inet_addr(target.c_str());
if (to.sin_addr.s_addr != (u_int)-1)
    hostname = target;
else 
{
    hp = gethostbyname(target.c_str());
    if (!hp)
    {
        cerr << "unknown host "<< target << endl;
        return -1;
    }
    to.sin_family = hp->h_addrtype;
    bcopy(hp->h_addr, (caddr_t)&to.sin_addr, hp->h_length);
    strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
    hostname = hnamebuf;
}
packlen = datalen + MAXIPLEN + MAXICMPLEN;
if ( (packet = (u_char *)malloc((u_int)packlen)) == NULL)
{
    cerr << "malloc error\n";
    return -1;
}

 /*
if ( (proto = getprotobyname("icmp")) == NULL)
{
    cerr << "unknown protocol icmp" << endl;
    return -1;
}
*/
if ( (s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
{
    perror("socket");   /* probably not running as superuser */
    return -1;
}

icp = (struct icmp *)outpack;
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = 12345;  /* seq and id must be reflected */
icp->icmp_id = getpid();


cc = datalen + ICMP_MINLEN;
icp->icmp_cksum = in_cksum((unsigned short *)icp,cc);

gettimeofday(&start, NULL);

i = sendto(s, (char *)outpack, cc, 0, (struct sockaddr*)&to, (socklen_t)sizeof(struct sockaddr_in));
if (i < 0 || i != cc)
{
    if (i < 0)
        perror("sendto error");
    cout << "wrote " << hostname << " " <<  cc << " chars, ret= " << i << endl;
}

// Watch stdin (fd 0) to see when it has input.
FD_ZERO(&rfds);
FD_SET(s, &rfds);
// Wait up to one seconds.
tv.tv_sec = 1;
tv.tv_usec = 0;

while(cont)
{
    retval = select(s+1, &rfds, NULL, NULL, &tv);
    if (retval == -1)
    {
        perror("select()");
        return -1;
    }
    else if (retval)
    {
        fromlen = sizeof(sockaddr_in);
        if ( (ret = recvfrom(s, (char *)packet, packlen, 0,(struct sockaddr *)&from, (socklen_t*)&fromlen)) < 0)
        {
            perror("recvfrom error");
            return -1;
        }

        // Check the IP header
        ip = (struct ip *)((char*)packet); 
        hlen = sizeof( struct ip ); 
        if (ret < (hlen + ICMP_MINLEN)) 
        { 
            cerr << "packet too short (" << ret  << " bytes) from " << hostname << endl;;
            return -1; 
        } 

        // Now the ICMP part 
        icp = (struct icmp *)(packet + hlen); 
        if (icp->icmp_type == ICMP_ECHOREPLY)
        {
            cout << "Recv: echo reply"<< endl;
            if (icp->icmp_seq != 12345)
            {
                cout << "received sequence # " << icp->icmp_seq << endl;
                continue;
            }
            if (icp->icmp_id != getpid())
            {
                cout << "received id " << icp->icmp_id << endl;
                continue;
            }
            cont = false;
        }
        else
        {
            cout << "Recv: not an echo reply" << endl;
            continue;
        }

        gettimeofday(&end, NULL);
        end_t = 1000000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);

        if(end_t < 1)
            end_t = 1;

        cout << "Elapsed time = " << end_t << " usec" << endl;
        return end_t;
    }
    else
    {
        cout << "No data within one seconds.\n";
        return 0;
    }
}
return 0;
}

Если я запускаю функцию пинга дважды, она дает сбой ровно в половине510. И картина точная.Вот результат после отметки 1020

socket: Too many open files 
ping returned -1

Я довольно плохо разбираюсь в сетевом программировании, но я даже не знаю, с чего начать для приведенного выше кода.

Я где-то пропускаю закрытие?

Функция ping взята из: http://www.linuxforums.org/forum/networking/60389-implementing-ping-c.html

Редактировать : Запуск Ubuntu 10.10, та же проблема в Fedora 13

Спасибо

Ответы [ 3 ]

5 голосов
/ 11 января 2011

Да, вам необходимо закрыть сокет с помощью close(s); перед выходом из функции.

4 голосов
/ 11 января 2011

При распределении ресурсов необходимо освободить их.

Как указывалось, вы должны закрыть розетки.

Но вам также необходимо освободить выделенную память (malloc, строка 40-ish).

Вам следует рассмотреть возможность использования memcpy вместо bcopy .

1 голос
/ 11 января 2011

Согласен с "раскрутить".

Обратите внимание, что вы запускаете функцию , а не программу. Следовательно, ваш процесс все еще жив, и все утечки памяти / ресурсов не освобождаются автоматически.

Как правило, если вы видите в коде вызов функции socket без соответствующей closesocket - это всегда должно поцарапать вам глаза!

...