一个非常实用的ping类

//ping.h

 

 #pragma once
#include <winsock2.h>
#pragma comment(lib, "WS2_32")

typedef struct icmp_hdr
{
    unsigned char   icmp_type;  // 消息类型
    unsigned char   icmp_code;  // 代码
    unsigned short  icmp_checksum; // 校验和
 // 下面是回显头
    unsigned short  icmp_id;  // 用来惟一标识此请求的ID号,通常设置为进程ID
    unsigned short  icmp_sequence; // 序列号
    unsigned long   icmp_timestamp; // 时间戳
} ICMP_HDR, *PICMP_HDR;

typedef struct _IPHeader  // 20字节的IP头
{
    UCHAR     iphVerLen;      // 版本号和头长度(各占4位)
    UCHAR     ipTOS;          // 服务类型
    USHORT    ipLength;       // 封包总长度,即整个IP报的长度
    USHORT    ipID;     // 封包标识,惟一标识发送的每一个数据报
    USHORT    ipFlags;       // 标志
    UCHAR     ipTTL;       // 生存时间,就是TTL
    UCHAR     ipProtocol;     // 协议,可能是TCP、UDP、ICMP等
    USHORT    ipChecksum;     // 校验和
    ULONG     ipSource;       // 源IP地址
    ULONG     ipDestination;  // 目标IP地址
} IPHeader, *PIPHeader;


// 定义TCP标志
#define   TCP_FIN   0x01
#define   TCP_SYN   0x02
#define   TCP_RST   0x04
#define   TCP_PSH   0x08
#define   TCP_ACK   0x10
#define   TCP_URG   0x20
#define   TCP_ACE   0x40
#define   TCP_CWR   0x80

typedef struct _TCPHeader  // 20字节的TCP头
{
 USHORT sourcePort;   // 16位源端口号
 USHORT destinationPort; // 16位目的端口号
 ULONG sequenceNumber;  // 32位序列号
 ULONG acknowledgeNumber; // 32位确认号
 UCHAR dataoffset;   // 高4位表示数据偏移
 UCHAR flags;    // 6位标志位
 USHORT windows;   // 16位窗口大小
 USHORT checksum;   // 16位校验和
 USHORT urgentPointer;  // 16位紧急数据偏移量
} TCPHeader, *PTCPHeader;

typedef struct _UDPHeader
{
 USHORT   sourcePort;  // 源端口号  
 USHORT   destinationPort;// 目的端口号  
 USHORT   len;   // 封包长度
 USHORT   checksum;  // 校验和
} UDPHeader, *PUDPHeader;

class ping
{
public:
 ping(void);
 ~ping(void);
 ICMP_HDR* icmp_head;
 SOCKET m_raw;
 void init(void);
 void start(void);
 BOOL setttl(SOCKET s,int ttl);
 BOOL settime(SOCKET s,int nTime, BOOL bRecv);
 char buff[44];
 bool serach(const char* ip);
 SOCKADDR_IN dest;
};
//ping.cpp

#include "StdAfx.h"
#include "./ping.h"
#include <winsock2.h>
#include <windows.h>
#include "Ws2tcpip.h"

USHORT checksum(USHORT* buff, int size)
{
 unsigned long cksum = 0;
 while(size>1)
 {
  cksum += *buff++;
  size -= sizeof(USHORT);
 }
 if(size)
 {
  cksum += *(UCHAR*)buff;
 }
 cksum = (cksum >> 16) + (cksum & 0xffff);
 cksum += (cksum >> 16);   
 return (USHORT)(~cksum);
}

ping::ping(void)
{
 this->icmp_head=(ICMP_HDR*)buff;
}

ping::~ping(void)
{
 this->icmp_head=NULL;
 ::closesocket(this->m_raw);
 WSACleanup();
}

void ping::init(void)
{
 WSADATA data;
 if(WSAStartup(MAKEWORD(2,2),&data)!=0)
 {
  printf("init error");
  exit(0);
 }
}

void ping::start(void)
{
 this->m_raw=::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 this->settime(this->m_raw,300,1);
 this->setttl(this->m_raw,2);
 icmp_head->icmp_type = 8; 
 icmp_head->icmp_code = 0;
 icmp_head->icmp_id = (USHORT)::GetCurrentProcessId();
 icmp_head->icmp_checksum = 0;
 icmp_head->icmp_sequence = 0;
 memset(&buff[sizeof(ICMP_HDR)], 'E', 32);
 dest.sin_family = AF_INET;
 dest.sin_port = htons(0);
 dest.sin_addr.S_un.S_addr = inet_addr("192.168.0.1");
}

BOOL ping::setttl(SOCKET s,int nValue)
{
 int ret = ::setsockopt(s, IPPROTO_IP, IP_TTL, (char*)&nValue, sizeof(nValue));
 return ret != SOCKET_ERROR;
 
}

BOOL ping::settime(SOCKET s, int nTime, BOOL bRecv)
{
 int ret = ::setsockopt(s, SOL_SOCKET,
  bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));
 return ret != SOCKET_ERROR;
}

bool ping::serach(const char* ip)
{
 USHORT nSeq = 0;
 char recvBuf[1024];
 SOCKADDR_IN from;
 int nLen = sizeof(from);
 dest.sin_addr.S_un.S_addr=::inet_addr(ip);
 int nRet;
 icmp_head->icmp_checksum = 0;
 icmp_head->icmp_timestamp = ::GetTickCount();
 icmp_head->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) + 32);
 int nTick = ::GetTickCount();
 nRet = ::sendto(this->m_raw, buff, sizeof(ICMP_HDR) + 32, 0, (SOCKADDR *)&dest, sizeof(dest));
 if(nRet == SOCKET_ERROR)
 {
  return 0;
 }
 nRet = ::recvfrom(this->m_raw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);
 int nTick1=::GetTickCount();
 if(nRet == SOCKET_ERROR)
 {
  if(::WSAGetLastError() == WSAETIMEDOUT)
  {
    
   return 0;
  }
   return 0;
 }
 ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20);
 if(pRecvIcmp->icmp_type != 0) 
 {
  return 0;
 }
 if(pRecvIcmp->icmp_id != ::GetCurrentProcessId())
 {
  return 0;
 }
 return true;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值