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

📄 framehandler.cpp

📁 对以太帧进行手动封装
💻 CPP
📖 第 1 页 / 共 2 页
字号:
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  内部辅助函数
//  功能:
//			根据数据段内容来计算crc校验码(此处采用CRC-8,即校验和为1Byte),通过调用generateCRC()完成
//  参数:
//			const FrameFront& frameFront : 该结构体为传入值,它保存着Ethernet帧的前导码、帧前定位符、
//										   目的地址、源地址、数据段长度等字段,在计算CRC过程中,需要
//										   用到该结构体的destMAC、srcMAC、dataLength共3个字段
//			const char* data : 该参数为传入值,它保存着Ethernet帧的数据段部分
//  返回值:
//			根据data计算出来的crc校验码(大小为1个字节)
///////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned char FrameHandler::getCRC(const FrameFront& frameFront, const unsigned char* data)
{
	// 计算CRC校验和所需要的数据是:目的MAC、源MAC、数据长度、数据段、以及填充字节(如果有的话)
	int realDataLength = (frameFront.dataLength[0] << 8) + frameFront.dataLength[1];
	int totalDataBytes = (realDataLength < MIN_DATA_LENGTH) ? MIN_DATA_LENGTH : realDataLength;  // data的总长度,即有效数据
																								 // 的长度 + 填充字节的长度

	// 计算CRC所需数据的长度
	int totalLength = sizeof(frameFront) - sizeof(frameFront.preamble) + totalDataBytes;

	// 计算CRC所需的数据
	unsigned char* dataForCRC = new unsigned char[totalLength];
	memcpy(dataForCRC, frameFront.destMAC, sizeof(frameFront) - sizeof(frameFront.preamble));
	memcpy(dataForCRC + sizeof(frameFront) - sizeof(frameFront.preamble), data, totalDataBytes);

	// 调用generateCRC函数来计算CRC校验码
	return generateCRC(dataForCRC, totalLength);
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  内部辅助函数,在getCRC()函数中被调用
//  功能:
//			计算CRC校验码
//	参数:
//			const unsigned char* dataForCRC : 计算CRC校验码所需要的输入数据
//			int length : 数据的长度(单位:Bytes)
//  返回值:
//			CRC校验码(1 Byte)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned char FrameHandler::generateCRC(const unsigned char* dataForCRC, int length)
{
	int totalLength = length + 1;
	unsigned char* input = new unsigned char[totalLength];
	memcpy(input, dataForCRC, length);
	input[totalLength - 1] = 0;  // 在输入数据的末尾添加一个字节0

	// 计算input字段的CRC校验码
	unsigned char crc = 0;         // crc校验码
	unsigned char genPoly = 0x07;  // 使用的生成多项式为G(X) = X8 + X2 + X1 + 1

	for (int i = 0; i < totalLength; i++)
	{
		for (unsigned char bitMask = 0x80; bitMask != 0; bitMask >>= 1)
		{
			if (crc & 0x80)  // 首位是1
			{
				crc <<= 1;
				if ((input[i] & bitMask) != 0)  // 新输入的一位为1
				{
					crc |= 0x01;
				}
				crc ^= genPoly;
			}
			else  // 首位是0
			{
				crc <<= 1;
				if ((input[i] & bitMask) != 0)  // 新输入的一位为1
				{
					crc |= 0x01;
				}
			}
		}
	}

	return crc;
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  内部辅助函数,该函数在package()中被调用
//  功能:
//			从fileName指定的文件中读取数据,放到字符数组data中
//  参数:
//			char* data : 存放待封装的数据,这些数据是从指定的文件中读取的,而不是由用户在控制台直接输入
//						 该参数为传出值
//  返回值:
//			如果成功的将文件中的数据加载到字符数组data中,则返回true
//			如果处理文件时发生了任何错误,则返回false
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FrameHandler::loadDataFromFile(char* data)
{
	cout << "\n==================================================\n";
	cout << "您选择了从文件中加载数据!\n请输入待封装的数据所在文件的文件名:";
	char* dataFileName = new char[257];  // 限定文件名的最大长度为256字节
	cin.getline(dataFileName, 257);  // 获取文件名

	// 打开数据文件
	FILE* dataFile = fopen(dataFileName, "rb");
	if (dataFile == NULL)
	{
		cout << "\n打开文件 [" << dataFileName << "] 失败!请确认文件名是否正确!\n";
		return false;
	}
	delete[] dataFileName;  // 文件名不再被使用,将其释放

	// 如果成功打开数据文件,则将其内容加载到字符数组data中
	// 首先获取数据文件的大小
	fseek(dataFile, 0, ios_base::end);
	int dataFileSize = ftell(dataFile);
	fseek(dataFile, 0, ios_base::beg);

	// 如果数组data能容纳整个文件,则全部读入;否则,将文件内容在MAX_DATA_LENGTH(即1500Bytes)后截断
	if (dataFileSize <= MAX_DATA_LENGTH)
	{
		fread(data, sizeof(char), dataFileSize, dataFile);
		data[dataFileSize] = '\0';
	}
	else
	{
		fread(data, sizeof(char), MAX_DATA_LENGTH, dataFile);
		data[MAX_DATA_LENGTH] = '\0';
		cout << "\n文件过大,读入数据在" << MAX_DATA_LENGTH << "字节后进行截断!\n";
	}
	fclose(dataFile);

	return true;
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  内部辅助函数,该函数在package()中被调用
//  功能:
//			填写Ethernet帧的前导码、帧前定位符、目的MAC、源MAC、数据段长度等字段
//  参数:
//			FrameFront& frameFront : 要设置的Ethernet帧(数据段之前的部分),该参数为传出值
//			const char* data : Ethernet帧的数据段,需要用该参数来计算数据段长度这一字段,该参数为传入值
//  返回值:
//			void
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FrameHandler::setFrameFront(FrameFront& frameFront, const char* data)
{
	// 将7Bytes的前导符设置为十六进制的AA-AA-AA-AA-AA-AA-AA
	for (int i = 0; i < 7; i++)
	{
		frameFront.preamble[i] = (unsigned char) 0xAA;
	}

	// 将帧前定位符设定为十六进制的AB
	frameFront.preamble[7] = (unsigned char) 0xAB;

	// 设定目的MAC为FF-FF-FF-FF-FF-FF,源MAC为00-16-76-B4-E4-77
	unsigned char srcMac[] = {0x00, 0x16, 0x76, 0xB4, 0xE4, 0x77};
	for (i = 0; i < 6; i++)
	{
		frameFront.destMAC[i] = (unsigned char) 0xFF;
		frameFront.srcMAC[i] = srcMac[i];
	}

	// 写入数据长度字段
	unsigned short dataLen = strlen(data);
	frameFront.dataLength[0] = (unsigned char) ((dataLen >> 8) & 0x00FF);
	frameFront.dataLength[1] = (unsigned char) (dataLen & 0x00FF);
}



/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  内部辅助函数,该函数在package()中被调用
//  功能:
//			将Ethernet帧保存到由成员变量filePath所指定的文件中
//  参数:
//			const FrameFront& frameFront : 前导码、帧前定位符、目的MAC、源MAC、数据长度等字段,该参数为传入值
//			const char* data : Ethernet帧的数据段,该参数为传入值
//			const unsigned char crc : CRC校验码,根据data字段计算出来的,该参数为传入值
//  返回值:
//			如果成功的将Ethernet帧写入filePath指定的文件中,则返回true
//			如果在写入时发生任何错误,则返回false
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FrameHandler::storeFrameInFile(const FrameFront& frameFront, const char* data, const unsigned char crc)
{
	// 以二进制追加的方式,打开filePath指定的文件
	FILE* file = fopen(filePath, "ab");

	// 打开文件失败,则输出错误信息,并返回false,表示函数失败
	if (file == NULL)
	{
		cout << "\n无法打开文件 [" << filePath << "] !请确认文件路径是否正确!\n";
		return false;  // 函数失败返回
	}

	// 将前导符、帧前定位符、目的MAC、源MAC、数据长度等字段写入文件中
	if (1 > fwrite(&frameFront, sizeof(frameFront), 1, file))
	{
		return false;
	}

	// 将数据段写入文件中
	int dataLen = strlen(data);
	if (dataLen > fwrite(data, sizeof(char), dataLen, file))
	{
		return false;
	}

	// 如果数据段的长度小于MIN_DATA_LENGTH(即46Bytes),则补齐最小长度
	if (dataLen < MIN_DATA_LENGTH)
	{
		unsigned char* fillBytes = new unsigned char[MIN_DATA_LENGTH - dataLen];
		memset(fillBytes, 0, MIN_DATA_LENGTH - dataLen);
		if ((MIN_DATA_LENGTH - dataLen) > fwrite(fillBytes, sizeof(unsigned char), MIN_DATA_LENGTH - dataLen, file))
		{
			return false;
		}
	}

	// 写入CRC校验码
	if (1 > fwrite(&crc, sizeof(unsigned char), 1, file))
	{
		return false;
	}

	// 至此,一个Ethernet帧已经全部写入文件filePath中,关闭文件并返回true
	fclose(file);
	return true;
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  内部辅助函数,在unpackage()函数中被调用
//  功能:
//			输出前导符、帧前定位符、目的地址、源地址、数据长度等信息
//  参数:
//			const FrameFront& frameFront : Ethernet帧的“前面部分”,即前导码、帧前定位符、目的MAC、源MAC、数据长度
//										   该参数为传入值
//  返回值:
//			void
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FrameHandler::outputFrameFront(const FrameFront& frameFront)
{
	// 输出前导码
	cout << setw(WIDTH) << "前导码" << ":";
	for (int i = 0; i < 7; i++)
	{
		cout << hexAlpha[frameFront.preamble[i] >> 4] << hexAlpha[frameFront.preamble[i] & 0x0F] << " ";
	}
	cout << endl;
				
	// 输出帧前定位符
	cout << setw(WIDTH) << "帧前定位符" << ":";
	cout << hexAlpha[frameFront.preamble[7] >> 4] << hexAlpha[frameFront.preamble[7] & 0x0F] << endl;
				
	// 输出目的地址
	cout << setw(WIDTH) << "目的地址" << ":";
	for (i = 0; i < 6; i++)
	{
		cout << hexAlpha[frameFront.destMAC[i] >> 4] << hexAlpha[frameFront.destMAC[i] & 0x0F];
		if (i != 5)
		{
			cout << '-';
		}
	}
	cout << endl;
				
	// 输出源地址
	cout << setw(WIDTH) << "源地址" << ":";
	for (i = 0; i < 6; i++)
	{
		cout << hexAlpha[frameFront.srcMAC[i] >> 4] << hexAlpha[frameFront.srcMAC[i] & 0x0F];
		if (i != 5)
		{
			cout << '-';
		}
	}
	cout << endl;

	// 输出长度字段
	cout << setw(WIDTH) << "长度字段" << ":";
	for (i = 0; i < 2; i++)
	{
		cout << hexAlpha[frameFront.dataLength[i] >> 4] << hexAlpha[frameFront.dataLength[i] & 0x0F] << " ";
	}
	cout << endl;
}

⌨️ 快捷键说明

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