我用Winsock2写了一个Ping的程序,

timeout = 1000;
int ret = setsockopt(m_Sock,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,
sizeof(timeout));
timeout = 1000;
ret = setsockopt(m_Sock,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,
sizeof(timeout))
设置超时
然后用
sendto(m_Sock,(char *)m_pIcmp,
DEF_PACKET+sizeof(ICMP_HANDER),
NULL,(struct sockaddr *)pAddr,sizeof(sockaddr));
        ret = recvfrom(m_Sock,(char *)m_pRec,MAX_PACKET,0,
(struct sockaddr*)&m_sockAddr,&len);
发送和接收数据,可是当向一个不连通的IP发数据时,没办法得到超时信息
ret并不出错,只是整个程序都挂了起来,一直没有响应,不知什么原因请问各位大虾,还有什么方法可以实现PING Windows自带的PING是怎么做的?

解决方案 »

  1.   

    MSDN的例子ping.c应该就是Windows自带的ping。
      

  2.   

    〈Windows网络编程〉第10章有个PING的例子,代码如下:
    CPing::CPing()
    {
      icmp_data = NULL;
      seq_no = 0;
      recvbuf = NULL;
      m_bRecordRout = FALSE;
      lpdest = NULL;
      datasize = DEF_PACKET_SIZE;  WSADATA wsaData;
      if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        {
            printf("WSAStartup() failed: %d\n", GetLastError());
            return ;
        }
      m_hSocket = INVALID_SOCKET;}CPing::~CPing()
    {}
      void CPing::Ping(int timeout)
    {   
     m_hSocket = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,
                               WSA_FLAG_OVERLAPPED);    if (m_hSocket == INVALID_SOCKET) 
        {
            printf("WSASocket() failed: %d\n", WSAGetLastError());
            return ;
        }    if (m_bRecordRout)
        {
            // Setup the IP option header to go out on every ICMP packet
            //
            ZeroMemory(&m_ipopt, sizeof(m_ipopt));
            m_ipopt.code = IP_RECORD_ROUTE; // Record route option
            m_ipopt.ptr  = 4;               // Point to the first addr offset
            m_ipopt.len  = 39;              // Length of option header
      
            int ret = setsockopt(m_hSocket, IPPROTO_IP, IP_OPTIONS, 
                (char *)&m_ipopt, sizeof(m_ipopt));
            if (ret == SOCKET_ERROR)
            {
                printf("setsockopt(IP_OPTIONS) failed: %d\n", 
                    WSAGetLastError());
            }
        }
        // Set the send/recv timeout values
        //
        int bread = setsockopt(m_hSocket, SOL_SOCKET, SO_RCVTIMEO, 
                    (char*)&timeout, sizeof(timeout));
        if(bread == SOCKET_ERROR) 
        {
            printf("setsockopt(SO_RCVTIMEO) failed: %d\n", 
                WSAGetLastError());
            return ;
        }
        timeout = 1000;
        bread = setsockopt(m_hSocket, SOL_SOCKET, SO_SNDTIMEO, 
                    (char*)&timeout, sizeof(timeout));
        if (bread == SOCKET_ERROR) 
        {
            printf("setsockopt(SO_SNDTIMEO) failed: %d\n", 
                WSAGetLastError());
            return ;
        }
        memset(&m_addrDest, 0, sizeof(m_addrDest));
        //
        // Resolve the endpoint's name if necessary
        //
        m_addrDest.sin_family = AF_INET;
        if ((m_addrDest.sin_addr.s_addr = inet_addr(lpdest)) == INADDR_NONE)
        {   
     struct hostent *hp = NULL;        if ((hp = gethostbyname(lpdest)) != NULL)
            {
                memcpy(&(m_addrDest.sin_addr), hp->h_addr, hp->h_length);
                m_addrDest.sin_family = hp->h_addrtype;
                printf("m_addrDest.sin_addr = %s\n", inet_ntoa(m_addrDest.sin_addr));
            }
            else
            {
                printf("gethostbyname() failed: %d\n", 
                    WSAGetLastError());
                return ;
            }
        }            // 
        // Create the ICMP packet
        //       
        datasize += sizeof(IcmpHeader);      icmp_data =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                      MAX_PACKET);
        recvbuf =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                      MAX_PACKET);
        if (!icmp_data) 
        {
            printf("HeapAlloc() failed: %d\n", GetLastError());
            return ;
        }
        memset(icmp_data,0,MAX_PACKET);
        FillICMPData(icmp_data,datasize);
        //
        // Start sending/receiving ICMP packets
        //
        while(1) 
        {
            static int nCount = 0;
            int        bwrote;
                    
            if (nCount++ == 4) 
                break;
                    
            ((IcmpHeader*)icmp_data)->i_cksum = 0;
            ((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
            ((IcmpHeader*)icmp_data)->i_seq = seq_no++;
            ((IcmpHeader*)icmp_data)->i_cksum = 
                checksum((USHORT*)icmp_data, datasize);        bwrote = sendto(m_hSocket, icmp_data, datasize, 0, 
                         (struct sockaddr*)&m_addrDest, sizeof(m_addrDest));
            if (bwrote == SOCKET_ERROR)
            {
                if (WSAGetLastError() == WSAETIMEDOUT) 
                {
                    printf("timed out\n");
                    continue;
                }
                printf("sendto() failed: %d\n", WSAGetLastError());
                return ;
            }
            if (bwrote < datasize) 
            {
                printf("Wrote %d bytes\n", bwrote);
            } int fromlen = sizeof(m_addrFrom);
            bread = recvfrom(m_hSocket, recvbuf, MAX_PACKET, 0, 
                        (struct sockaddr*)&m_addrFrom, &fromlen);
            if (bread == SOCKET_ERROR)
            {
                if (WSAGetLastError() == WSAETIMEDOUT) 
                {
                    printf("timed out\n");
                    continue;
                }
                printf("recvfrom() failed: %d\n", WSAGetLastError());
                return ;
            }
            DecodeICMPHeader(recvbuf, bread, &m_addrFrom);
            
        }
    }void CPing::Cleanup()
    {
      if (m_hSocket != INVALID_SOCKET) 
            closesocket(m_hSocket);
        HeapFree(GetProcessHeap(), 0, recvbuf);
        HeapFree(GetProcessHeap(), 0, icmp_data);    WSACleanup();
        return ;
    }void CPing::FillICMPData(char *icmp_data, int datasize)
    {
       IcmpHeader *icmp_hdr = NULL;
        char       *datapart = NULL;    icmp_hdr = (IcmpHeader*)icmp_data;
        icmp_hdr->i_type = ICMP_ECHO;        // Request an ICMP echo
        icmp_hdr->i_code = 0;
        icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
        icmp_hdr->i_cksum = 0;
        icmp_hdr->i_seq = 0;
      
        datapart = icmp_data + sizeof(IcmpHeader);
    }
      

  3.   

    void CPing::DecodeIPOptions(char *buf, int bytes)
    {
         IpOptionHeader *ipopt = NULL;
        IN_ADDR         inaddr;
        int             i;
        HOSTENT        *host = NULL;    ipopt = (IpOptionHeader *)(buf + 20);    printf("RR:   ");
        for(i = 0; i < (ipopt->ptr / 4) - 1; i++)
        {
            inaddr.S_un.S_addr = ipopt->addr[i];
            if (i != 0)
                printf("      ");
            host = gethostbyaddr((char *)&inaddr.S_un.S_addr,
                        sizeof(inaddr.S_un.S_addr), AF_INET);
            if (host)
                printf("(%-15s) %s\n", inet_ntoa(inaddr), host->h_name);
            else
                printf("(%-15s)\n", inet_ntoa(inaddr));
        }
        return;
    }USHORT CPing::checksum(USHORT *buffer, int size)
    {
       unsigned long cksum=0;    while (size > 1) 
        {
            cksum += *buffer++;
            size -= sizeof(USHORT);
        }
        if (size) 
        {
            cksum += *(UCHAR*)buffer;
        }
        cksum = (cksum >> 16) + (cksum & 0xffff);
        cksum += (cksum >>16);
        return (USHORT)(~cksum);
    }void CPing::ValidateArgs(int argc,char** argv)
    {
        int    i;
        
        for(i = 1; i < argc; i++)
        {
            if ((argv[i][0] == '-') || (argv[i][0] == '/'))
            {
                switch (tolower(argv[i][1]))
                {
                    case 'r':        // Record route option
                        m_bRecordRout = TRUE;
                        break;
                    default:
                        usage(argv[0]);
                        break;
                }
            }
            else if (isdigit(argv[i][0]))
                datasize = atoi(argv[i]);
            else
                lpdest = argv[i];
        }
    }void CPing::DecodeICMPHeader(char *buf, int bytes, SOCKADDR_IN *from)
    {
       IpHeader       *iphdr = NULL;
        IcmpHeader     *icmphdr = NULL;
        unsigned short  iphdrlen;
        DWORD           tick;
        static   int    icmpcount = 0;    iphdr = (IpHeader *)buf;
    // Number of 32-bit words * 4 = bytes
        iphdrlen = iphdr->h_len * 4;
        tick = GetTickCount();    if ((iphdrlen == MAX_IP_HDR_SIZE) && (!icmpcount))
            DecodeIPOptions(buf, bytes);    if (bytes  < iphdrlen + ICMP_MIN) 
        {
            printf("Too few bytes from %s\n", 
                inet_ntoa(from->sin_addr));
        }
        icmphdr = (IcmpHeader*)(buf + iphdrlen);    if (icmphdr->i_type != ICMP_ECHOREPLY) 
        {
            printf("nonecho type %d recvd\n", icmphdr->i_type);
            return;
        }
        // Make sure this is an ICMP reply to something we sent!
        //
        if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) 
        {
            printf("someone else's packet!\n");
            return ;
        }
        printf("%d bytes from %s:", bytes, inet_ntoa(from->sin_addr));
        printf(" icmp_seq = %d. ", icmphdr->i_seq);
        printf(" time: %d ms", tick - icmphdr->timestamp);
        printf("\n");    icmpcount++;
        return;
    }void CPing::usage(char *progname)
    {
       printf("usage: ping -r <host> [data size]\n");
        printf("       -r           record route\n");
        printf("        host        remote machine to ping\n");
        printf("        datasize    can be up to 1KB\n");
        ExitProcess(-1);
    }