⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pingsimulator.cpp

📁 用rawsocket实现简单的ping程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#pragma comment(lib, "Ws2_32.lib")  // 加载Ws2_32.lib

#include "packetheader.h"  // 自定义的头文件
#include <iostream>
#include <iomanip>
#include <cstring>
#include <Winsock2.h>
#include <ws2tcpip.h>

using namespace std;

// *************************** begin 常量定义 ************************************
const unsigned char ICMP_ECHO_REQUEST = 8;  // Ping请求报文的类型字段为8
const unsigned char ICMP_ECHO_REPLY = 0;    // Ping响应报文的类型字段为0
const int DEFAULT_ICMP_DATA_SIZE = 32;      // Ping请求报文数据段的默认大小
const int MAX_ICMP_PACKET_SIZE = 1024;      // Ping请求报文的最大值
// *************************** end 常量定义 **************************************


// *************************** begin 变量定义 ************************************
// 命令提供的选项,以及选项的值
bool hasParam_t = false;           // 选项"-t",表示一直ping,直到输入Ctrl-C强行终止
bool hasParam_a = false;           // 选项"-a",表示将目标主机的IP地址解析成主机名
bool hasParam_n_count = false;     // 选项"-n count",表示Ping的次数
long totalPingRequests = 4;        // 对每台主机ping的次数,默认为4
bool hasParam_l_size = false;      // 选项"-l size",设定发送缓冲区的大小
long sendBufferSize = 32;          // 发送缓冲区的大小
bool hasParam_i_ttl = false;       // 选项"-i TTL",设定TTL的值
unsigned char ttl = 255;                     // 生存时间
bool hasParam_v_tos = false;       // 选项"-v TOS",设定TOS的值
unsigned char tos = 0;                       // 服务类型
bool hasParam_w_timeout = false;   // 选项"-w timeout",设定接收的超时时间(单位:ms)
long timeout = 5000;               // 接收Ping响应报文的超时时间,默认为5秒
bool hasParam_1 = false;           // 选项"-1",表示仅有一台目标主机
bool hasParam_2 = false;           // 选项"-2",表示有多台目标主机
bool hasDestHost = false;          // 如果获得了目标主机的有效IP,则为true;否则为false
bool onlyOneDestHost = true;       // 如果为true,则表示仅有一台目标主机,否则有多台
unsigned long destIP;              // 目标主机的IP地址
char destHostName[256] = {0};      // 目的主机名

// 原始套接字
SOCKET rawSocket;

// 控制及状态变量
int numberOfHostsToPing = 0;       // 等待被Ping的主机的数目
long pingRequestsToSend = 0;       // 对于指定的目标主机,需要发送的Ping请求报文的数目
unsigned short sequenceNumber = 0; // Ping请求报文的序号
// *************************** end 变量定义 **************************************


// *************************** begin 函数声明 ************************************
bool parseCmdlineParams(int argc, char* argv[]);  // 解析命令行参数
void showUsage();  // 显示程序的用法以及选项等信息
bool checkParams();  // 检测命令行参数是否存在冲突
void setSocketOptions();  // 设置socket选项,如TTL、TOS、timeout等
void ping();  // 对目标主机进行Ping操作
void fillIcmpPacket(char* pIcmpPacket, int size);  // 填充Ping请求报文
unsigned short getIcmpChecksum(unsigned short* pData, int size);  // 计算ICMP报文的校验和字段
void showDestHostInfo();  // 显示目标主机的相关信息,如IP地址、主机名等
void ipToString(unsigned long ip, char* ipstr);  // 将unsigned long型的IP地址转换成点分十进制形式的字符串
void showStatisticsInfo(const StatisticsRecord& statisticsRecord);  // 显示Ping的统计信息
bool parseReceivedPacket(const char* pRecvBuffer, PingRecord& pingRecord);  // 对收到的数据包进行解析
void showReply(const PingRecord& pingRecord);  // 显示接收到的Ping响应信息
void setStatisticsRecord(StatisticsRecord& statisticsRecord, const PingRecord& pingRecord);  // 更新统计信息
BOOL WINAPI ctrlHandler(DWORD dwCtrlType);  // 自定义函数,用来处理快捷键 Ctrl-C 和 Ctrl-Break
// *************************** end 函数声明 **************************************



// *******************************************************************************
// 主函数
//		功	能:程序的入口函数
//		参	数:1. argc : 命令行参数的个数
//				2. argv : 命令行参数
//		返回值:当程序正常结束时,返回0;否则返回其他值
// *******************************************************************************

int main(int argc, char* argv[])
{
	// 更改控制台的标题
	char* consoleTitle = "PingSimulator - 使用ICMP协议实现简单的Ping程序 - (学号:2120080354  姓名:刘洪涛)";
	SetConsoleTitle(consoleTitle);

	// 更改控制台的背景色为黑色,前景色为淡绿色
	system("color 0A");

	// 初始化Windows Socket dll
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		cout << "\n初始化Windows Socket dll失败.\n";
		system("color");  // 恢复控制台的默认背景色和前景色
		return -1;
	}

	// 首先对命令行参数进行解析
	if (!parseCmdlineParams(argc, argv))
	{
		// 如果解析命令行参数出错,则退出
		system("color");  // 恢复控制台的默认背景色和前景色
		return -1;
	}

	// 检测参数是否有冲突的情况
	if (!checkParams())
	{
		// 如果参数存在冲突,则报错并退出
		system("color");  // 恢复控制台的默认背景色和前景色
		return -1;
	}

	// 创建原始套接字
	rawSocket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);
	if (INVALID_SOCKET == rawSocket)
	{
		cout << "\n创建原始套接字失败.\n";
		system("color");  // 恢复控制台的默认背景色和前景色
		return -1;
	}

	// 根据命令行参数对socket选项进行设置
	setSocketOptions();

	// 添加一个函数ctrlHandler,用来响应Ctrl-C和Ctrl-Break消息
	SetConsoleCtrlHandler(ctrlHandler, true);

	// 进行Ping操作
	ping();

	// 将ctrlHandler函数从处理列表中移除
	SetConsoleCtrlHandler(ctrlHandler, false);

	// 恢复控制台的默认背景色和前景色
	system("color");

	// 注销Windows Socket dll
	return WSACleanup();
}



// ********************************************************************************
// 解析命令行参数
//		功	能:对命令行参数进行解析,从中提取出目标主机的IP地址以及其他选项等信息
//		参	数:1. argc : 命令行参数的个数
//				2. argv : 命令行参数
//		返回值:如果解析过程中发生错误,则返回false;否则返回true
// ********************************************************************************

bool parseCmdlineParams(int argc, char* argv[])
{
	if (1 == argc)  // 如果没有附加参数,则输出命令的使用方法
	{
		showUsage();
		return false;
	}
	else  // 如果有附加参数,则对其进行解析
	{
		for (int i = 1; i < argc; i++)
		{
			if (0 == strcmp(argv[i], "-t"))  // 处理"-t"选项
			{
				hasParam_t = true;
				continue;
			}
			else if (0 == strcmp(argv[i], "-a"))  // 处理"-a"选项
			{
				hasParam_a = true;
				continue;
			}
			else if (0 == strcmp(argv[i], "-n"))  // 处理"-n count"选项
			{
				hasParam_n_count = true;
				if (i + 1 < argc)  // 如果选项字段没有结束
				{
					// 获取count字段
					totalPingRequests = atol(argv[++i]);
					if (totalPingRequests > 0)
					{
						// 已经成功获取count字段,转去处理下一个参数
						continue;
					}
					else  // count字段无效
					{
						cout << "\n错误:\n";
						cout << "    选项\"-n count\"中的count字段无效,请输入PingSimulator.exe查看详细用法.\n";
						return false;
					}
				}
				else
				{
					cout << "\n错误:\n";
					cout << "    未在选项\"-n count\"中找到count字段,请输入PingSimulator.exe查看详细用法.\n";
					return false;
				}
			}
			else if (0 == strcmp(argv[i], "-l"))  // 处理选项"-l size"
			{
				hasParam_l_size = true;
				if (i + 1 < argc)
				{
					// 获取size字段
					sendBufferSize = atoi(argv[++i]);
					if (sendBufferSize >= 32 && sendBufferSize <= 65500)
					{
						// 已正确获取size字段,转去处理下一个选项
						continue;
					}
					else
					{
						cout << "\n错误:\n";
						cout << "    选项\"-l size\"中的size字段无效,请输入PingSimulator.exe查看详细用法.\n";
						return false;
					}
				}
				else
				{
					cout << "\n错误:\n";
					cout << "    未在选项\"-l size\"中找到size字段,请输入PingSimulator.exe查看详细用法.\n";
					return false;
				}
			}
			else if (0 == strcmp(argv[i], "-i"))  // 处理选项"-i TTL"
			{
				hasParam_i_ttl = true;
				if (i + 1 < argc)
				{
					// 获取TTL字段
					ttl = atoi(argv[++i]);
					if (ttl >= 1 && ttl <= 255)
					{
						// 已正确获取TTL字段,转去处理下一个选项
						continue;
					}
					else
					{
						cout << "\n错误:\n";
						cout << "    选项\"-i TTL\"中的TTL字段无效,请输入PingSimulator.exe查看详细用法.\n";
						return false;
					}
				}
				else
				{
					cout << "\n错误:\n";
					cout << "    未在选项\"-i TTL\"中找到TTL字段,请输入PingSimulator.exe查看详细用法.\n";
					return false;
				}
			}
			else if (0 == strcmp(argv[i], "-v"))  // 处理选项"-v TOS"
			{
				hasParam_v_tos = true;
				if (i + 1 < argc)
				{
					// 获取TOS字段
					tos = atoi(argv[++i]);
					continue;
				}
				else
				{
					cout << "\n错误:\n";
					cout << "    未在选项\"-v TOS\"中找到TOS字段,请输入PingSimulator.exe查看详细用法.\n";
					return false;
				}
			}
			else if (0 == strcmp(argv[i], "-w"))  // 处理选项"-w timeout"
			{
				hasParam_w_timeout = true;
				if (i + 1 < argc)
				{
					// 获取timeout字段
					timeout = atoi(argv[++i]);
					if (timeout >= 1)
					{
						// 成功获取到timeout字段,转去处理下一个选项
						continue;
					}
					else
					{
						cout << "\n错误:\n";
						cout << "    选项\"-w timeout\"中的timeout字段无效,请输入PingSimulator.exe查看详细用法.\n";
						return false;
					}
				}
				else
				{
					cout << "\n错误:\n";
					cout << "    未在选项\"-w timeout\"中找到timeout字段,请输入PingSimulator.exe查看详细用法.\n";
					return false;
				}
			}
			else if (0 == strcmp(argv[i], "-1"))  // 处理选项"-1"
			{
				hasParam_1 = true;
				continue;
			}
			else if (0 == strcmp(argv[i], "-2"))  // 处理选项"-2"
			{
				hasParam_2 = true;
				continue;
			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -