📄 unitping.cpp
字号:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "UnitPing.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;
}
//-----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -