免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1454 | 回复: 0
打印 上一主题 下一主题

linux下ping命令的c++实现 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-01 00:55 |只看该作者 |倒序浏览

一 原理
    ping命令工作在ip层,在程序中通过raw
scket进行数据的收发,发数据时不需要填充ip头部,但是在接收数据时需要过滤掉ip头部信息。icmp头部重要的字段有三
个,type,code,checksum,其中type表示命令的类型,对于ping命令来说,type的值为8表示发送icmp,type值为0表示
是icmp的回包,code表示type下的子命令,对于ping命令来说,code的值为0。checksum字段表示icmp包的校验字段,校验方法
为对icmp的所有字段取和再取反码。
二 实现代码:
   /*ping.h*/
#ifndef __SAM_PING_
#define __SAM_PING_
#include    "stdlib.h"
#include    "string.h"
#include    "stdio.h"
#include    "fcntl.h"
#include    "errno.h"
#include    "signal.h"
#include    "sys/types.h"
#include    "sys/socket.h"
#include    "sys/time.h"
#include    "netinet/in.h"
#include    "arpa/inet.h"
#include    "netdb.h"
#define MAXBUFFLEN 200
#define ICMP_ECHO 8 /* icmp echo requir */
#define ICMP_ECHOREPLY 0 /* icmp echo reply */
#define ICMP_HEADSIZE 8 /* icmp packet header size */
#define IP_HEADSIZE 20 /* ip packet header size */
#pragma  pack(1)
typedef struct tagIpHead /* icmp packet header */
{
    u_char ip_verlen; /* ip version and ip header lenth*/
    u_char ip_tos; /* ip type of service */
    u_short ip_len; /* ip packet lenghth */
    u_short ip_id; /* ip packet identification */
    u_short ip_fragoff; /* ip packet fragment and offset */
    u_char ip_ttl; /* ip packet time to live */
    u_char ip_proto; /* ip packet protocol type */
    u_short ip_chksum; /* ip packet header checksum */
    u_long ip_src_addr; /* ip source ip adress */
    u_long ip_dst_addr; /* ip destination ip adress */
} IPHEAD;
typedef struct tagIcmpHead /* icmp header */
{
    u_char icmp_type; /* icmp service type */
    /* 8 echo require, 0 echo reply */
    u_char icmp_code; /* icmp header code */
    u_short icmp_chksum; /* icmp header chksum */
    u_short icmp_id; /* icmp packet identification */
    u_short icmp_seq; /* icmp packet sequent */
    u_char icmp_data[1]; /* icmp data, use as pointer */
} ICMPHEAD;
#pragma pack()
class CICMP
{
private:
    int m_iSocket;
    int m_iPkgSize;
    long m_iSendTime;             /*发送ping包的时间戳*/
    long m_iRecvTime;             /*接收ping包的时间戳*/
    long m_iDelay;
    IPHEAD m_stIpHead;
    ICMPHEAD m_stIcmpHead;
    char m_szIcmpData[MAXBUFFLEN];
protected:
    long TimeNow();
    bool validChkSum(ushort* buffer,int size);
    u_short ChkSum(u_short* pIcmpData,int iDataLen);
    int ParseRecv(IPHEAD* pHeader,int size);
public:
    CICMP(int pkgSize = 0):m_iPkgSize(pkgSize){memset(m_szIcmpData,0,MAXBUFFLEN);}
    int CreateRawSocket();
    int Ping(const char* szIp,int pkgSize);
    int Stat();
    int Receive();
};
#endif
/*ping.cpp*/
#include "ping.h"
#include
#include
using namespace std;
u_short CICMP::ChkSum( u_short * buffer, int size )
/* for check sum of icmp header */
{
    unsigned long cksum=0;
    while(size >1)
    {
        cksum+=*buffer++;
        size-=sizeof(unsigned short);
    }
    if(size) cksum+=*(unsigned short*)buffer;
    cksum=(cksum >> 16)+(cksum&0xffff);
    cksum+=(cksum >>16);
    return (unsigned short)(~cksum);
}
bool CICMP::validChkSum(unsigned short *buffer, int size)
{
    unsigned long cksum=0;
    while(size >1)
    {
        cksum+=*buffer++;
        size-=sizeof(unsigned short);
    }
    if(size) cksum+=*(unsigned short*)buffer;
    cksum=(cksum >> 16)+(cksum&0xffff);
    cksum+=(cksum >>16);
    return ((unsigned short)cksum == 0xFFFF);
}
int CICMP::CreateRawSocket()
{
    this->m_iSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if(this->m_iSocket h_addr, &descAddr.sin_addr, h->h_length);
    }
    else
    {
        /* bad ip adress or host name */
        /* exit */
        fprintf( stderr, "bad IP or host\n" );
        return -1;
    }
    cout icmp_type = ICMP_ECHO;
    pIcmpHead->icmp_code = 0;
    pIcmpHead->icmp_id = 1;
    pIcmpHead->icmp_seq = 1;
    pIcmpHead->icmp_chksum = 0;
    /* store time information as icmp packet content, 4 bytes */
    /* u may store other information instead */
    *((long *)pIcmpHead->icmp_data) = TimeNow();
    this->m_iSendTime = TimeNow();
    //iPacketSize = ICMP_HEADSIZE + 4; /* icmp packet length */
    iPacketSize = sizeof(ICMPHEAD) + 3;
    /* icmp header check sum */
    pIcmpHead->icmp_chksum = this->ChkSum((u_short *)pIcmpHead, iPacketSize );
    /* remember the time when send for calculate round trip time */
    //lSendTime = time_now();
    /* send the icmp packet to des host */
    //cout m_iSocket,buf,MAXBUFFLEN - 1,0,(struct sockaddr *)&fromAddr,(socklen_t*)&namelen);
    if(size == -1)
    {
        cout ip_verlen & 0x0f) ip_ttl; /* time to live param */
    /* get the icmp header information */
    ICMPHEAD *pIcmpHead = (ICMPHEAD *)(buf + iIpHeadLen);
    /* not icmp echo reply packet, give it up */
    if (pIcmpHead->icmp_type != ICMP_ECHOREPLY)
    {
        cout icmp_id != 1 || pIcmpHead->icmp_seq != 1)
    {
        cout TimeNow();
    this->m_iRecvTime = iCurTime;
    ParseRecv((IPHEAD *)buf,size);
    delete buf;
    return 0;
}
int CICMP::ParseRecv(IPHEAD * pHeader,int size)
{
    memcpy(&m_stIpHead,pHeader,sizeof(IPHEAD));
    char* szTmp = (char*)pHeader;
    char* ptrIcmp = szTmp + sizeof(IPHEAD);
    memcpy(&m_stIcmpHead,ptrIcmp,sizeof(ICMPHEAD));
    /* get the data of icmp*/
    szTmp += sizeof(ICMPHEAD) - 1;
    int iDataLen = size - sizeof(IPHEAD) - sizeof(ICMPHEAD) + 1;
    memcpy(m_szIcmpData,szTmp,iDataLen);
    return 0;
}
int CICMP::Stat()
{
    struct in_addr recvFrom;
    memcpy(&recvFrom,&m_stIpHead.ip_src_addr,4);
    u_char ipTTL = this->m_stIpHead.ip_ttl;
    //int iSendTime = atoi(this->m_szIcmpData);
    int iDelayTime = (int)((m_iRecvTime - m_iSendTime)/1000);
    char szBuff[100] = {0};
    char* szIp = inet_ntoa(recvFrom);
    if(szIp == NULL)
    {
        cout << "get src ip failed" << endl;
        return -1;
    }
    sprintf(szBuff,"recv from %s,delay=%ds,TTL=%d",szIp,iDelayTime,ipTTL);
    cout << szBuff << endl;
    return 0;
}
测试程序
int main(int argc,char** argv)
{
    if(argc != 2)
    {
        cout << "argument: host" << endl;
        return 0;
    }
    char* szIp = argv[1];
    CICMP icmp;
    if(icmp.CreateRawSocket() != 0)
    {
        cout << "create socket failed" << endl;
        return 0;
    }
    if(icmp.Ping(szIp,4) != 0)
    {
        cout << "ping failed" << endl;
        return 0;
    }
    //cout << "send success ,begin to receive" << endl;
    if(icmp.Receive() != 0)
    {
        return 0;
    }
    icmp.Stat();
    return 0;
}
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/94080/showart_1886747.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP