ping程式(C++builder+Win32API)

來源:互聯網
上載者:User

///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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.