?? framehandler.cpp
字號(hào):
#include "framehandler.h"
#include <iostream>
#include <cstring>
#include <iomanip>
using std::cout;
using std::endl;
using std::ios_base;
using std::setw;
using std::cin;
using std::ios;
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 構(gòu)造函數(shù)
// 參數(shù):
// bool isPackging : 該參數(shù)表示當(dāng)前實(shí)例要執(zhí)行何種操作,為true表示[幀封裝],為false表示[幀解析]
// const char* filePath : 根據(jù)isPackaging的不同,該參數(shù)有不同意義
// 當(dāng)前者為true時(shí),則將封裝好的幀保存到filePath指定的文件中
// 當(dāng)前者為false時(shí),則從filePath指定的文件中解析Ethernet幀
////////////////////////////////////////////////////////////////////////////////////////////////////////////
FrameHandler::FrameHandler(bool isPackaging, const char* filePath)
{
// 設(shè)置操作類型,true表示幀封裝,false表示幀解析
this->isPackaging = isPackaging;
// 保存文件路徑
// 當(dāng)進(jìn)行幀封裝時(shí),表示封裝后的幀所存放的文件路徑;當(dāng)進(jìn)行幀解析時(shí),表示待解析的文件的路徑
this->filePath = new char[strlen(filePath) + 1];
strcpy(this->filePath, filePath);
// 對(duì)hexAlpha[]數(shù)組進(jìn)行賦值
for (int i = 0; i < 10; i++)
{
hexAlpha[i] = char ('0' + i);
}
for (i = 10; i < 16; i++)
{
hexAlpha[i] = char ('A' + i - 10);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
// 析構(gòu)函數(shù)
////////////////////////////////////////////////////////////////////////////////////////////////
FrameHandler::~FrameHandler()
{
// 釋放資源
if (filePath != NULL)
{
delete[] filePath;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// 該函數(shù)為對(duì)外接口,可被FrameHandler的實(shí)例直接調(diào)用
// 功能:
// 完成[幀封裝]操作,并將封裝后的幀保存在filePath指定的文件中
// 參數(shù):
// void
// 返回值:
// 如果封裝成功,則返回true
// 如果封裝失敗,則返回false
///////////////////////////////////////////////////////////////////////////////////////////////
bool FrameHandler::package()
{
// 如果創(chuàng)建實(shí)例時(shí)指定的操作類型不是“幀封裝”,則調(diào)用該函數(shù)失敗
if (isPackaging == false)
{
return false;
}
// 下面進(jìn)行幀封裝的操作
// 輸出操作信息
cout << "操作類型:幀封裝\n保存封裝結(jié)果的文件路徑:" << filePath
<< "\n\n==================================================\n\n";
// 讓用戶輸入一段信息,以回車結(jié)束
cout << "請(qǐng)輸入一段信息,以回車結(jié)束\n(如果直接輸入回車,則可以從文件中讀取數(shù)據(jù),并將其封裝成Ethernet幀):" << endl;
char* data = new char[MAX_DATA_LENGTH + 1];
cin.getline(data, MAX_DATA_LENGTH + 1);
// 如果用戶直接輸入了回車(即data中不含任何數(shù)據(jù)),則認(rèn)為用戶要從文件中加載數(shù)據(jù),提示用戶輸入文件的路徑
if (strlen(data) == 0)
{
// 從文件中加載數(shù)據(jù)
if (!loadDataFromFile(data))
{
cout << "\n從文件中加載數(shù)據(jù)失敗!\n";
delete[] data;
return false;
}
else
{
cout << "\n==================================================\n"
<< "從文件中讀入的數(shù)據(jù)如下:\n\n" << data << endl;
}
}
// 填充前導(dǎo)符、幀前定位符、目的MAC、源MAC、數(shù)據(jù)長(zhǎng)度等信息
FrameFront frameFront;
setFrameFront(frameFront, data);
// 計(jì)算CRC校驗(yàn)碼(需要用到目的MAC、源MAC、數(shù)據(jù)長(zhǎng)度、數(shù)據(jù)段、以及填充字節(jié)(如果有的話))
int totalBytes = (strlen(data) < MIN_DATA_LENGTH) ? MIN_DATA_LENGTH : strlen(data);
unsigned char* dataWithFillBytes = new unsigned char[totalBytes];
memcpy(dataWithFillBytes, data, strlen(data));
if (strlen(data) < MIN_DATA_LENGTH)
{
memset(dataWithFillBytes + strlen(data), 0, MIN_DATA_LENGTH - strlen(data));
}
unsigned char crc = getCRC(frameFront, dataWithFillBytes);
// 將Ethernet幀保存到文件filePath中
if (!storeFrameInFile(frameFront, data, crc))
{
cout << "\n向文件 [" << filePath << "] 寫入數(shù)據(jù)失敗!\n";
return false;
}
else
{
// 寫入成功,釋放所有資源并返回true
delete[] data;
cout << "\n==================================================\n";
cout << "幀封裝完畢!\n封裝后的Ethernet幀存放在文件 [" << filePath << "] 中!\n\n";
return true;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 該函數(shù)為對(duì)外接口,可被FrameHandler的實(shí)例直接調(diào)用
// 功能:
// 完成[幀解析]操作,將filePath指定的文件進(jìn)行解析,從中提取出Ethernet幀的相關(guān)信息
// 參數(shù):
// void
// 返回值:
// 如果分析文件成功,則返回true
// 如果在處理文件的過(guò)程中出現(xiàn)任何錯(cuò)誤,則返回false
////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool FrameHandler::unpackage()
{
// 如果創(chuàng)建實(shí)例時(shí)指定的操作類型不是“幀解析”,則調(diào)用該函數(shù)失敗
if (isPackaging == true)
{
return false;
}
// 下面進(jìn)行幀解析的操作
// 以二進(jìn)制讀的方式打開待解析的文件
FILE* file = fopen(filePath, "rb");
// 如果打開文件失敗,則輸出錯(cuò)誤信息并返回false值
if (NULL == file)
{
cout << "\n無(wú)法打開文件 [" << filePath << "] !請(qǐng)確認(rèn)文件路徑是否正確!\n";
return false;
}
// 如果成功的打開了文件,則執(zhí)行下面的操作
// 輸出提示信息
cout << "操作類型:Ethernet幀解析\n待解析的文件路徑:" << filePath << endl;
int frameCounter = 0; // 記錄已經(jīng)解析的幀的數(shù)目
FrameFront frameFront; // 保存讀入的幀的前面部分(即前導(dǎo)符、界定符、目的mac、源mac、數(shù)據(jù)長(zhǎng)度)
int count = sizeof(frameFront) / sizeof(unsigned char); // FrameFront結(jié)構(gòu)體包含的字節(jié)數(shù)
// 從文件中讀取數(shù)據(jù)并分析,直到文件尾或者發(fā)生錯(cuò)誤
while (count == fread(&frameFront, sizeof(unsigned char), count, file))
{
if (isLegalPreamble(frameFront.preamble))
{
frameCounter++;
cout << "\n=========================第" << frameCounter << "個(gè)幀=========================\n";
// 設(shè)定輸出格式為左對(duì)齊
cout.setf(ios::left);
// 輸出幀的序號(hào)
cout << setw(WIDTH) << "序號(hào)" << ":" << frameCounter << endl;
// 輸出前導(dǎo)碼、幀前定位符、目的地址、源地址、數(shù)據(jù)長(zhǎng)度等
outputFrameFront(frameFront);
// 計(jì)算數(shù)據(jù)段的長(zhǎng)度(不包括填充字節(jié))
int dataLength = (frameFront.dataLength[0] << 8) + frameFront.dataLength[1];
// 計(jì)算數(shù)據(jù)段與填充字節(jié)的總長(zhǎng)度
int totalBytes = (dataLength < MIN_DATA_LENGTH) ? MIN_DATA_LENGTH : dataLength;
// 讀取數(shù)據(jù)段與填充字節(jié)(如果有的話)
unsigned char* data = new unsigned char[totalBytes];
fread(data, sizeof(unsigned char), totalBytes, file);
// 輸出數(shù)據(jù)段的有效內(nèi)容(不包括填充字節(jié))
cout << setw(WIDTH) << "數(shù)據(jù)字段" << ":";
char* dataToShow = new char[dataLength + 1];
memcpy(dataToShow, data, dataLength);
dataToShow[dataLength] = 0;
cout << dataToShow << endl;
delete[] dataToShow;
// 獲取幀中的CRC校驗(yàn)字段
unsigned char crcInFrame;
fread(&crcInFrame, sizeof(unsigned char), 1, file);
// 計(jì)算CRC校驗(yàn)碼(需要用到目的MAC、源MAC、數(shù)據(jù)長(zhǎng)度、以及具體的數(shù)據(jù)段)
unsigned char realCRC = getCRC(frameFront, data);
// 輸出CRC校驗(yàn)信息,以及是否接收等
cout << setw(WIDTH) << "CRC校驗(yàn)" << ":";
if (crcInFrame == realCRC)
{
cout << "(正確):" << hexAlpha[crcInFrame >> 4] << hexAlpha[crcInFrame & 0x0F] << endl;
cout << setw(WIDTH) << "狀態(tài)" << ":Accept" << endl;
}
else
{
// 輸出 (錯(cuò)誤):[原校驗(yàn)碼] 應(yīng)為 [正確的校驗(yàn)碼]
cout << "(錯(cuò)誤):[" << hexAlpha[crcInFrame >> 4] << hexAlpha[crcInFrame & 0x0F] << "] 應(yīng)為 ["
<< hexAlpha[realCRC >> 4] << hexAlpha[realCRC & 0x0F] << "]" << endl;
cout << setw(WIDTH) << "狀態(tài)" << ":Discard" << endl;
}
// 釋放資源
delete[] data;
// 繼續(xù)尋找下一個(gè)幀
continue;
}
else
{
fseek(file, -(count - 1), ios_base::cur);
}
}
// 解析完畢,輸出發(fā)現(xiàn)的幀的數(shù)目
if (frameCounter == 0)
{
cout << "\n==================================================\n";
cout << "解析完畢,但沒(méi)有發(fā)現(xiàn)任何Ethernet幀!\n\n";
}
else
{
cout << "\n==================================================\n";
cout << "解析完畢,共找到上述" << frameCounter << "個(gè)Ethernet幀!\n\n";
}
// 關(guān)閉文件,然后返回
fclose(file);
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 內(nèi)部輔助函數(shù)
// 功能:
// 檢查讀入的數(shù)據(jù)是否包含正確的前導(dǎo)符以及幀前定位符,正確值應(yīng)為十六進(jìn)制的AA-AA-AA-AA-AA-AA-AA-AB
// 參數(shù):
// const unsigned char* preamble : 該參數(shù)為傳入值,表示7個(gè)字節(jié)的前導(dǎo)碼 + 1個(gè)字節(jié)的幀前定位符
// 返回值:
// 如果前導(dǎo)碼為十六進(jìn)制的AA-AA-AA-AA-AA-AA-AA,且 幀前定位符為十六進(jìn)制的AB,則返回true
// 否則返回false
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool FrameHandler::isLegalPreamble(const unsigned char* preamble)
{
// 首先檢查前7個(gè)字節(jié)是否為十六進(jìn)制的AA-AA-AA-AA-AA-AA-AA
for (int i = 0; i < 6; i++)
{
if(preamble[i] != 0xAA)
{
return false;
}
}
// 再檢查最后一個(gè)字節(jié)是否為十六進(jìn)制的AB
return (preamble[7] == 0xAB) ? true : false;
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -