ping命令 仿源码实现 以及几个 命令的 使用

ping localhost

ping 主机名

ping 主机IP

ping -a 主机IP

ping -t  主机IP

#include <iostream>
#include <cstdio>
#include <string>
#include <WinSock2.h>

#pragma comment(lib, "ws2_32.lib")//winsock库

using namespace std;

struct ICMPheader
{
    unsigned char    byType;
    unsigned char    byCode;
    unsigned short    nChecksum;
    unsigned short    nId;
    unsigned short    nSequence;
};

struct IPheader
{
    unsigned char    byVerLen; 
    unsigned char    byTos; 
    unsigned short    nTotalLength; 
    unsigned short    nId; 
    unsigned short    nOffset; 
    unsigned char    byTtl; 
    unsigned char    byProtocol; 
    unsigned short    nChecksum; 
    unsigned int    nSrcAddr; 
    unsigned int    nDestAddr; 
};

unsigned short checkSum (char *pBuffer, int nLen)
{
    unsigned short nWord;
    unsigned int nSum = 0;
    int i;

    //Make 16 bit words out of every two adjacent 8 bit words in the packet
    //and add them up
    for (i = 0; i < nLen; i = i + 2)
    {
        nWord =((pBuffer [i] << 8)& 0xFF00) + (pBuffer [i + 1] & 0xFF);
        nSum = nSum + (unsigned int)nWord;    
    }

    //Take only 16 bits out of the 32 bit sum and add up the carries
    while (nSum >> 16)
    {
        nSum = (nSum & 0xFFFF) + (nSum >> 16);
    }

    //One's complement the result
    nSum = ~nSum;

    return ((unsigned short) nSum);
}

int main()
{
    string str_dest_addr;
    SOCKET sock_raw;
    SOCKADDR_IN dest_addr;
    SOCKADDR_IN from_addr;

    char sendBuffer[1024] = {0};
    char recvBuffer[1024] = {0};

    WSADATA wsaData;

    ::WSAStartup(MAKEWORD(2,2), &wsaData);

    sock_raw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

    int timeout = 1000;

    setsockopt(sock_raw, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
    setsockopt(sock_raw, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));

    dest_addr.sin_family = AF_INET;
    memset(&dest_addr.sin_zero, 0, 8);

    while( cout << "ping>")
    {
        cin >> str_dest_addr;
        int nSeq = 0;
        int nPacketSent = 0;
        int nPacketReceived = 0;
        int nTotalRoundTime = 0;
        int nMaxRoundTime = 0;
        int nMinRoundTime = -1;
        if((dest_addr.sin_addr.S_un.S_addr = inet_addr(str_dest_addr.c_str())) == INADDR_NONE)
        {
            struct hostent *hp = NULL;
            if((hp = gethostbyname(str_dest_addr.c_str())) != NULL)
            {
                memcpy(&(dest_addr.sin_addr), hp->h_addr_list[0],hp->h_length);
            }
            else
            {
                cout << "can not find the host!" << endl;
                continue;
            }
        }

        while( nPacketSent < 4)
        {
            nPacketSent++;
            ICMPheader* pIcmpHeader = (ICMPheader*)sendBuffer;

            pIcmpHeader->byType = 8;
            pIcmpHeader->byCode = 0;
            pIcmpHeader->nId = (USHORT)::GetCurrentProcessId();
            pIcmpHeader->nChecksum = 0;
        
            pIcmpHeader->nSequence = htons(nSeq++);
            memset(sendBuffer + sizeof(ICMPheader), '*', 32);
            pIcmpHeader->nChecksum = htons(checkSum(sendBuffer, sizeof(ICMPheader) + 32));
            
            int nRet = sendto(sock_raw, sendBuffer, sizeof(ICMPheader) + 32, 0, (SOCKADDR*)&dest_addr, sizeof(SOCKADDR_IN));

            if(nRet == SOCKET_ERROR)
            {
                cout << "send error:" << ::WSAGetLastError() << endl;
                break;
            }

            unsigned long dwSendTime = ::GetTickCount();

            int fromLen = sizeof(SOCKADDR_IN);

            nRet = recvfrom(sock_raw, recvBuffer, 1024, 0, (SOCKADDR*)&from_addr,&fromLen);

            if(nRet == SOCKET_ERROR)
            {
                if(::WSAGetLastError() == WSAETIMEDOUT)
                {
                    cout << "Request time out" << endl;
                    continue;
                }

                break;
            }

            IPheader* ipHdr = (IPheader*)recvBuffer;
            ICMPheader* icmpHdrRet = (ICMPheader*)(recvBuffer + sizeof(IPheader));

            if( icmpHdrRet->byCode == 0 &&
                icmpHdrRet->nId == pIcmpHeader->nId &&
                icmpHdrRet->nSequence == pIcmpHeader->nSequence)
            {

                nPacketReceived++;
                unsigned long dwRecvTime = ::GetTickCount();
                int nRoundTime = dwRecvTime - dwSendTime;
                nTotalRoundTime += nRoundTime;

                if(nMinRoundTime == -1)
                {
                    nMinRoundTime = nRoundTime;
                    nMaxRoundTime = nRoundTime;
                }

                if( nRoundTime < nMinRoundTime)
                {
                    nMinRoundTime = nRoundTime;
                }
                
                if( nRoundTime > nMaxRoundTime)
                {
                    nMaxRoundTime = nRoundTime;
                }
            

                cout << "Reply from " << inet_ntoa(from_addr.sin_addr) << ": bytes = " << nRet - sizeof(ICMPheader) - sizeof(IPheader) << ", time = " << nRoundTime << "ms, TTL = " << (int)ipHdr->byTtl << endl;
            }
            else
            {
                cout << "The echo reply is not correct!" << endl;
            }

            Sleep(1000);
        }


        cout << endl << "Ping statistics for " << inet_ntoa(from_addr.sin_addr) << ":" << endl << "\t" << "Packets:sent = " << nPacketSent << ", Received = "
            << nPacketReceived << ", Lost = " << (nPacketSent - nPacketReceived) << "(" << ((float)(nPacketSent - nPacketReceived) /nPacketSent) * 100 << "% loss)" << endl;

        if(nPacketReceived)
        {
            cout << "\rApproximate round trip times in milli-seconds:" << endl << '\t' << "Minimum = " << nMinRoundTime << 
            "ms, Maximum = " << nMaxRoundTime << "ms, Average = " << (float)nTotalRoundTime /nPacketReceived << "ms" << endl;
        }

    }

    ::closesocket(sock_raw);
    ::WSACleanup();

    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值