1020次尝试后Ping功能失败

时间:2011-01-11 12:04:19

标签: c++ sockets ping

我有一个需要不断ping设备的程序

然而,这个ping函数在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;
}

如果我运行两次ping函数,它会在正好一半的510处失败。而且模式是准确的。这是1020标记后的输出

socket: Too many open files 
ping returned -1

我在网络编程方面非常糟糕,但我甚至不知道上面的代码从哪里开始。

我错过了某个地方吗?

ping函数取自:http://www.linuxforums.org/forum/networking/60389-implementing-ping-c.html

编辑:在Fedora 13上运行Ubuntu 10.10,同样的问题

由于

3 个答案:

答案 0 :(得分:5)

是的,您需要在退出该功能之前使用close(s);关闭套接字。

答案 1 :(得分:4)

分配资源时,您需要确保免费

正如unwind指出的那样,你必须关闭套接字。

但你还需要释放分配的内存(malloc,40-line)。

您应该考虑使用memcpy代替bcopy

答案 2 :(得分:1)

同意“放松”。

请注意,您运行功能,而不是程序。因此,您的进程仍然存在,并且不会自动释放所有内存/资源泄漏。

作为一般规则,如果您在代码中看到调用socket函数而没有相应的closesocket - 这必须始终刮伤您的眼睛!