ping

来源:互联网 发布:mips 64位 网络处理器 编辑:程序博客网 时间:2024/04/26 13:44

///unit.cpp/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{

Edit1->Text="127.0.0.1";
   Edit2->Text="64";
   Edit3->Text="1000";
   Memo1->Lines->Clear();
   SeqIndex = 0;
   RecvPack = 0;
}
//---------------------------------------------------------------------------


void __fastcall TForm1::Button2Click(TObject *Sender)
{
Close();        
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
IniSocket();//初始化/善后工作
  Ping();//调用Ping函数
}
//---------------------------------------------------------------------------
void TForm1::Ping()//完成ping功能
{
  struct hostent * hp;               
  char * strHost;//主机地址
  int nDataSize;//ICMP数据包长度
  int timeout;
  unsigned int addr = 0;
  unsigned int dw;

  WORD wVersionRequested;
  WSADATA wsaData;
  int err;
  wVersionRequested = MAKEWORD( 2, 2 );
  err = WSAStartup( wVersionRequested, &wsaData );
  if ( err != 0 )
  {
    Memo1->Lines->Add("无法建立WinSock,请检查是否缺少相关动态链接库");
    return;
  }
  if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 )
  {
    Memo1->Lines->Add("无法建立WinSock,请检查是否缺少相关动态链接库");
    WSACleanup();
    return;
  }

  IniSocket();
  //建立一个用于收发ICMP报的socket对象
  if (INVALID_SOCKET == (SockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)))
  {
     Memo1->Lines->Add("无法建立socket对象");
     return ;
  }
  timeout = Edit3->Text.ToInt();//设置最大等待时间
  if ((SOCKET_ERROR == setsockopt(SockRaw, SOL_SOCKET, SO_RCVTIMEO,
   (char*)&timeout, sizeof(timeout))) ||
   (SOCKET_ERROR == setsockopt(SockRaw, SOL_SOCKET, SO_SNDTIMEO,
   (char*)&timeout, sizeof(timeout))))
  {
      Memo1->Lines->Add("Socket错误");
      return ;
  }

  memset(&saDest,0,sizeof(saDest));//初始化为0
  //inet_addr()将点分地址转换为整数地址
  strHost=Edit1->Text.c_str();
  if (INADDR_NONE == (addr = inet_addr(strHost)))
  {
     //gethostbyname()解析域名地址
     if (NULL == (hp = gethostbyname(strHost)))
     {
        Memo1->Lines->Add("地址有误");
       return;
     }
     else
     {
      saDest.sin_family = hp->h_addrtype;
      memcpy(&(saDest.sin_addr),hp->h_addr,hp->h_length);
     }
  }
  else
  {
     saDest.sin_family = AF_INET;
     saDest.sin_addr.s_addr = addr;
  }
  PacketSize=Edit2->Text.ToInt();
  nDataSize = PacketSize + sizeof(ICMPHEADER);
  pICMPData = new char[nDataSize];
  pRecvBuf = new char[nDataSize + MAXIPHEADER];
  memset(pICMPData, 0, nDataSize);//置0
  Fill_ICMP_Data(pICMPData, nDataSize);//填充ICMP报文
  SeqIndex = 0;//本报文序号
  RecvPack = 0;//清空接收到报文数目
  Timer1->Enabled=true;//定时器开始工作
}


void TForm1::IniSocket()//完成初始化/善后工作
{
  if (INVALID_SOCKET != SockRaw)
  {
     closesocket(SockRaw);
     SockRaw = INVALID_SOCKET;
  }
  if (NULL != pICMPData)
  {
     delete pICMPData;
     pICMPData = NULL;
  }
  if (NULL != pRecvBuf)
  {
     delete pRecvBuf;
     pRecvBuf = NULL;
  }
}

 


void TForm1::Fill_ICMP_Data(char *pICMPData, int nDataSize)
{
  ICMPHEADER *pICMPHdr;
  char *pDataPart;
  pICMPHdr = (ICMPHEADER*)pICMPData;
  pICMPHdr->i_type = ICMP_ECHO;
  pICMPHdr->i_code = 0;
  pICMPHdr->i_id = (USHORT)GetCurrentProcessId();
  pICMPHdr->i_seq = 0;
  pDataPart = pICMPData + sizeof(ICMPHEADER);
  memset(pDataPart, 'E', nDataSize - sizeof(ICMPHEADER));
}
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
//定时发出ICMP报文
   int nError;
   int nWrite, nRead;
   sockaddr_in from;//定义远端的Socket链接地址
   int nfromLen = sizeof(from);
   int nDataSize = PacketSize + sizeof(ICMPHEADER);
   //如果超过了定义的最大发送报文数目,就停止ping
   if (SeqIndex>=MAXNUM)
   {
    int Lost;//报文丢失比率
    Lost = (SeqIndex - RecvPack) * 100 / SeqIndex;
        Memo1->Lines->Add("Lost= "+AnsiString(Lost)+"%");
        Timer1->Enabled=false;
        IniSocket();
        return;
   }
   //如果没有超过定义的最大发送报文数,就继续ping
   ((ICMPHEADER*)pICMPData)->i_cksum = 0;
   ((ICMPHEADER*)pICMPData)->timestamp = GetTickCount();//时间戳
   ((ICMPHEADER*)pICMPData)->i_seq = 0xffff & (SeqIndex ++);//给报文编号
   ((ICMPHEADER*)pICMPData)->i_cksum = CheckSum((USHORT*)pICMPData,
                 nDataSize);//校验和

    if (SOCKET_ERROR == (nWrite = sendto(SockRaw, pICMPData, nDataSize, 0,
  (struct sockaddr*)&saDest, sizeof(saDest))))
    {
     if (WSAETIMEDOUT == (nError = WSAGetLastError()))
     {
            Memo1->Lines->Add("超时错误");
     }
        else
     {
            Memo1->Lines->Add("发送报文错误");
            Timer1->Enabled=false;//停止发送报文
     }
     return;
    }
    if (SOCKET_ERROR == (nRead = recvfrom(SockRaw, pRecvBuf,
  nDataSize + MAXIPHEADER, 0, (struct sockaddr*)&from, &nfromLen)))
    {
     if (WSAETIMEDOUT == (nError = WSAGetLastError()))
     {
            Memo1->Lines->Add("超时错误"); 
     } else
     {
            Memo1->Lines->Add("接收数据错误");
            Timer1->Enabled=false;//停止发送报文
     }
        return;
    }
    Decode_Resp(pRecvBuf, nRead, &from);
}

 

USHORT TForm1::CheckSum(USHORT *DataBuffer, int Size)//校验和函数
{
   unsigned long Sum = 0;
   while (1 < Size)
   {
    Sum += *DataBuffer++;
    Size -= sizeof(USHORT);
   }
   if (Size)
   Sum += *(UCHAR*)DataBuffer;
   Sum = (Sum >> 16) + (Sum & 0xffff);
   Sum += (Sum >>16);
   return (USHORT)(~Sum);
}
//---------------------------------------------------------------------------
bool TForm1::Decode_Resp(char *Buffer, int Bytes, sockaddr_in *SocketFrom)
{  //程序接收到的是一个IP报文,为了得到ICMP报文,还必须分解此IP报
   IPHEADER *iphdr;
   ICMPHEADER *icmphdr;
   unsigned short iphdrlen;
   iphdr = (IPHEADER *)Buffer;
   AnsiString StrOfPing;
   //iphdrlen是以byte为单位,而iphdr是32bit为单位
   iphdrlen = iphdr->h_len << 2 ;
   if ((iphdrlen + ICMP_MIN) > Bytes)
   {
      Memo1->Lines->Add("收到字节数目太少");
      return false;
   }
   icmphdr = (ICMPHEADER*)(Buffer + iphdrlen);
   if (ICMP_ECHOREPLY != icmphdr->i_type)
   {
      Memo1->Lines->Add("类型有错");
      return false;
   }
   if (icmphdr->i_id != (USHORT)GetCurrentProcessId())
   {
      Memo1->Lines->Add("不是本程序的数据报");
      return false;
   }
   ++ RecvPack;//报文正确,累加器加一
   StrOfPing="Reply from "+ AnsiString(inet_ntoa(SocketFrom->sin_addr))
             +":"+" Seq "+AnsiString(icmphdr->i_seq)
             +" bytes="+AnsiString(Bytes)
             +" times="+AnsiString(GetTickCount()-icmphdr->timestamp)+"ms"
             +" TTL:"+ AnsiString(iphdr->ttl);
   Memo1->Lines->Add(StrOfPing);
   return true;
}
//---------------------------------------------------------------------------

 

 

//////////////////////unit1.h///////////////////////////////////////////////////////

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <winsock2.h>
#define ICMP_ECHO  8
#define ICMP_ECHOREPLY         0

#define ICMP_MIN  8  //ICMP报头的最小字节数
#define MAXIPHEADER  60  //IP数据报的最大字节数
#define MAXNUM                  10              //定义发送的报文的次数数
// IP header

typedef struct tagIPHEADER {
 unsigned char h_len:4;  // length of the header
 unsigned char version:4; // Version of IP
 unsigned char tos;  // Type of service
 unsigned short total_len; // total length of the packet
        unsigned short ident;  // unique identifier
 unsigned short frag_and_flags; // flags
 unsigned char  ttl;
 unsigned char proto;  // protocol (TCP, UDP etc)
 unsigned short checksum; // IP checksum

 unsigned int sourceIP;
 unsigned int destIP;

} IPHEADER;
// ICMP header
typedef struct tagICMPHEADER
{
 BYTE i_type;
 BYTE i_code;
 USHORT i_cksum;
 USHORT i_id;
 USHORT i_seq;
 ULONG timestamp; //时间戳
} ICMPHEADER;
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
        TMemo *Memo1;
        TPanel *Panel1;
        TLabel *Label1;
        TLabel *Label2;
        TLabel *Label3;
        TEdit *Edit1;
        TEdit *Edit2;
        TEdit *Edit3;
        TButton *Button1;
        TButton *Button2;
        TTimer *Timer1;
        void __fastcall Button2Click(TObject *Sender);
        void __fastcall Button1Click(TObject *Sender);
        void __fastcall Timer1Timer(TObject *Sender);
private:

SOCKET SockRaw;//Socket对象
        char* pICMPData;//指向ICMP数据缓冲区
        char* pRecvBuf;//指向接收数据缓冲区
        sockaddr_in saDest;//存储Ping的目的地址
        int PacketSize;//数据长度
        int SeqIndex;//报文序号
        int RecvPack;//接收到的报文数目

        void Ping();
        void IniSocket();
        void Fill_ICMP_Data(char *pICMPData, int nDataSize);
        USHORT CheckSum(USHORT *DataBuffer, int Size);//校验和函数
        //数据解码函数
        bool Decode_Resp(char *Buffer, int Bytes, sockaddr_in *SocketFrom);

 // User declarations
public:  // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
 

原创粉丝点击