?? pingsimulator.cpp
字號:
// 類型字段設置成Ping Request
pIcmpHeader->type = ICMP_ECHO_REQUEST;
// 代碼字段設置為0
pIcmpHeader->code = 0;
// 校驗和暫時置為0
pIcmpHeader->checksum = 0;
// id字段為當前進程的id
pIcmpHeader->id = htons((unsigned short) GetCurrentProcessId());
// 填充序號字段
pIcmpHeader->sequenceNumber = htons(sequenceNumber);
// 填充數據段
memset(pIcmpPacket + sizeof (ICMPHeader), 'E', DEFAULT_ICMP_DATA_SIZE);
// 計算校驗和
pIcmpHeader->checksum = getIcmpChecksum((unsigned short*) pIcmpPacket, size);
}
// ************************************************************************************
// 計算校驗和
// 功 能:計算ICMP報文的校驗和字段
// 參 數:1. pData : 存放ICMP報文的緩沖區
// 2. size : 緩沖區的大小
// 返回值:整個ICMP報文的校驗和
// ************************************************************************************
unsigned short getIcmpChecksum(unsigned short* pData, int size)
{
// 首先將校驗和置為0
unsigned long checksum = 0;
// 以2字節為單位反復累加
while (size > 1)
{
checksum += * (pData++);
size -= sizeof (unsigned short);
}
// 如果總字節數為奇數,則加上最后一個字節
if (size > 0)
{
checksum += * (unsigned char*) pData;
}
// 將高16位(進位)與低16位累加
checksum = (checksum >> 16) + (checksum & 0xFFFF);
// 將上一步中可能產生的高16位進位再次與低16位累加
checksum += (checksum >> 16);
// 返回16位的網際校驗和
return (unsigned short) (~checksum);
}
// *****************************************************************************
// 顯示目標主機的信息
// 功 能:顯示待Ping主機的IP地址、主機名等信息
// 參 數:無
// 返回值:void
// *****************************************************************************
void showDestHostInfo()
{
// 如果指定了"-a"選項,則獲取主機名
if (hasParam_a && 0 == strlen(destHostName))
{
// 根據IP地址獲取主機
hostent* pDestHost = gethostbyaddr((char*) &destIP, sizeof (destIP), AF_INET);
// 獲取主機名
if (pDestHost != NULL && pDestHost->h_name != NULL)
{
strcpy(destHostName, pDestHost->h_name);
}
}
// 將IP地址轉換成字符串
char ipstr[16] = {0};
ipToString(htonl(destIP), ipstr);
// 輸出主機名和IP地址等信息
cout << "\n--------------------------------------------------------------------------------";
if (strlen(destHostName) != 0)
{
cout << "Pinging " << destHostName << " [" << ipstr << "] with " << sendBufferSize << " bytes of data :\n\n";
memset(destHostName, 0, sizeof (destHostName));
}
else
{
cout << "Pinging " << ipstr << " with " << sendBufferSize << " bytes of data :\n\n";
}
}
// *******************************************************************************
// 將ip地址轉換成點分十進制的形式
// 功 能:將unsigned long型的IP地址轉換成點分十進制形式的字符串
// 參 數:1. ip : 待轉換的IP地址
// 2. ipstr : 字符緩沖區,用來保存轉換后的字符串
// 返回值:void
// *******************************************************************************
void ipToString(unsigned long ip, char* ipstr)
{
sprintf(ipstr, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
}
// *******************************************************************************
// 顯示Ping的統計信息
// 功 能:顯示對某一臺主機的Ping操作的統計信息
// 參 數:statisticsRecord : 待顯示的統計信息,包括發包數、收包數、往返時間等
// 返回值:void
// *******************************************************************************
void showStatisticsInfo(const StatisticsRecord& statisticsRecord)
{
// 將目標主機的IP地址轉換成點分十進制的形式
char ipstr[16] = {0};
ipToString(ntohl(destIP), ipstr);
// 獲得總發包數、總收包數
unsigned long sent = statisticsRecord.totalRequests;
unsigned long received = statisticsRecord.totalResponses;
unsigned long lost = sent - received;
// 輸出收發包的統計信息
cout << "\nPing statistics for " << ipstr << " :\n";
cout << " Packets : Sent = " << sent << ", Received = " << received
<< ", Lost = " << lost << " (" << (unsigned long) (((double) lost / sent) * 100) << "% loss).\n";
// 輸出時間統計信息
if (received > 0)
{
cout << "Approximate round trip times in milli-seconds :\n";
cout << " Minimum = " << statisticsRecord.minTime << "ms, Maximum = "
<< statisticsRecord.maxTime << "ms, Average = "
<< (statisticsRecord.totalTime / received) << "ms.\n";
}
cout << "--------------------------------------------------------------------------------\n";
}
// **************************************************************************************
// 對接收到的數據包進行解析
// 功 能:解析接收到的數據包,判斷是否為正確的Ping響應報文,如果是,則提取相關字段的值
// 參 數:1. pRecvBuffer : 接收緩沖區
// 2. pingRecord : 保存有待Ping主機的IP、Ping請求報文的id、序號,以及ttl等參數
// 返回值:如果接收到的是正確的Ping響應報文,則返回true;否則返回false
// **************************************************************************************
bool parseReceivedPacket(const char* pRecvBuffer, PingRecord& pingRecord)
{
IPHeader* pIPHeader = (IPHeader*) pRecvBuffer;
// 如果不是IPv4報文,或者上層協議不是ICMP,則返回false
if ((pIPHeader->versionAndHeaderLength >> 4) != 4 || (pIPHeader->protocol != 1))
{
return false;
}
// 如果不是正在Ping的主機的IP地址,則返回false
if (pIPHeader->srcIP != pingRecord.ipToPing)
{
return false;
}
// 計算IP報頭的長度
int ipHeaderLength = (pIPHeader->versionAndHeaderLength & 0x0F) * 4;
// 得到ICMP報頭
ICMPHeader* pIcmpHeader = (ICMPHeader*) (pRecvBuffer + ipHeaderLength);
// 如果不是ICMP回顯響應報文,則返回false
if (pIcmpHeader->type != ICMP_ECHO_REPLY)
{
return false;
}
// 如果id和序號不正確,則返回false
if (pIcmpHeader->id != pingRecord.id || pIcmpHeader->sequenceNumber != pingRecord.sequenceNumber)
{
return false;
}
// 記錄往返時間,保存TTL
pingRecord.roundTripTime = GetTickCount() - pingRecord.roundTripTime;
pingRecord.ttl = pIPHeader->timeToLive;
// 接收到了正確的Ping響應報文,返回true
return true;
}
// **************************************************************************************
// 顯示響應信息
// 功 能:當收到正確的Ping響應報文時,調用該函數來顯示響應信息,如往返時間、ttl等
// 參 數:pingRecord : 保存有往返時間、ttl等參數的結構體變量
// 返回值:void
// **************************************************************************************
void showReply(const PingRecord& pingRecord)
{
// 將ip地址轉換成點分十進制的形式
char ipstr[16] = {0};
ipToString(ntohl(pingRecord.ipToPing), ipstr);
// 輸出相關信息
cout << "Reply from " << ipstr << " : bytes=" << sendBufferSize << " ";
if (pingRecord.roundTripTime < 1)
{
cout << "time<1ms ";
}
else
{
cout << "time=" << pingRecord.roundTripTime << "ms ";
}
cout << "TTL=" << (int) pingRecord.ttl << endl;
}
// **************************************************************************************
// 更新Ping的統計信息
// 功 能:當收到正確的Ping響應報文時,更新統計信息,如收包數、往返時間等
// 參 數:1. statisticsRecord : 保存統計信息的結構體變量
// 2. pingRecord : 保存有往返時間、ttl等值的結構體變量
// 返回值:void
// **************************************************************************************
void setStatisticsRecord(StatisticsRecord& statisticsRecord, const PingRecord& pingRecord)
{
// 將接收到的Ping響應報文的數目加1
statisticsRecord.totalResponses++;
// 更新總的往返時間
statisticsRecord.totalTime += pingRecord.roundTripTime;
// 更新最大往返時間
if (statisticsRecord.maxTime < 0)
{
statisticsRecord.maxTime = pingRecord.roundTripTime;
}
else
{
statisticsRecord.maxTime = ((pingRecord.roundTripTime > statisticsRecord.maxTime) ? pingRecord.roundTripTime : statisticsRecord.maxTime);
}
// 更新最小往返時間
if (statisticsRecord.minTime < 0)
{
statisticsRecord.minTime = pingRecord.roundTripTime;
}
else
{
statisticsRecord.minTime = ((pingRecord.roundTripTime < statisticsRecord.minTime) ? pingRecord.roundTripTime : statisticsRecord.minTime);
}
}
// *************************************************************************************
// Ctrl-C和Ctrl-Break的消息處理函數
// 功 能:自定義Ctrl-C和Ctrl-Break的處理方法
// 參 數:dwCtrlType : 快捷鍵的類型
// 返回值:如果只想自己處理,而不由系統加以干涉,則返回TRUE;否則返回FALSE
// *************************************************************************************
BOOL WINAPI ctrlHandler(DWORD dwCtrlType)
{
// 如果是Ctrl-C,則終止對當前主機的Ping;如果有多臺目標主機,則繼續Ping下一臺
if (CTRL_C_EVENT == dwCtrlType)
{
pingRequestsToSend = 0;
return TRUE;
}
// 如果是Ctrl-Break,則終止對所有主機的Ping操作
if (CTRL_BREAK_EVENT == dwCtrlType)
{
pingRequestsToSend = 0;
numberOfHostsToPing = 0;
return TRUE;
}
// 如果不是Ctrl-C或者Ctrl-Break,則交由系統來處理
return FALSE;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -