?? frameparser.cpp
字號:
#include<fstream.h> // 用于文件操作
#include<stdlib.h> // 用于程序流程控制
////////////////////////////////////////////////////////////////////////////////
// CRC校驗,在上一輪校驗的基礎上繼續作8位CRC校驗
//
// 輸入參數:
// chCurrByte 低8位數據有效,記錄了上一次CRC校驗的余數
// chNextByte 低8位數據有效,記錄了本次要繼續校驗的一個字節
//
// 傳出參數:
// chCurrByte 低8位數據有效,記錄了本次CRC校驗的余數
////////////////////////////////////////////////////////////////////////////////
void checkCRC(int &chCurrByte, int chNextByte)
{
// CRC循環:每次調用進行8次循環,處理一個字節的數據。
for (int nMask = 0x80; nMask > 0; nMask >>= 1)
{
if ((chCurrByte & 0x80) != 0) // 首位為1:移位,并進行異或運算
{
chCurrByte <<= 1; // 移一位
if ( (chNextByte & nMask) != 0) // 補一位
{
chCurrByte |= 1;
}
chCurrByte ^= 7; // 首位已經移出,僅對低8位進行異或運算,7的二進制為0000,0111
}
else // 首位為0,只移位,不進行異或運算
{
chCurrByte <<= 1; // 移一位
if ( (chNextByte & nMask) != 0) // 補一位
{
chCurrByte |= 1;
}
}
}
}
void main(int argc, char* argv[])
{
// 檢測命令行參數的正確性
if (argc != 2)
{
cout << "請以幀封裝包文件為參數重新執行程序" << endl;
exit(0);
}
// 檢測輸入文件是否存在,并可以按所需的權限和方式打開
ifstream file(argv[1], ios::in|ios::binary|ios::nocreate);
if (!file.is_open())
{
cout << "無法打開幀封裝包文件,請檢查文件是否存在并且未損壞" << endl;
exit(0);
}
// 變量聲明及初始化
int nSN = 1; // 幀序號
int nCheck = 0; // 校驗碼
int nCurrDataOffset = 22; // 幀頭偏移量
int nCurrDataLength = 0; // 數據字段長度
bool bParseCont = true; // 是否繼續對輸入文件進行解析
int nFileEnd = 0; // 輸入文件的長度
// 計算輸入文件的長度
file.seekg(0, ios::end); // 把文件指針移到文件的末尾
nFileEnd = file.tellg(); // 取得輸入文件的長度
file.seekg(0, ios::beg); // 文件指針位置初始化
cout.fill('0'); // 顯示初始化
cout.setf(ios::uppercase); // 以大寫字母輸出
// 定位到輸入文件中的第一個有效幀
// 從文件頭開始,找到第一個連續的“AA-AA-AA-AA-AA-AA-AA-AB”
while ( true )
{
for (int j = 0; j < 7; j++) // 找7個連續的0xaa
{
if (file.tellg() >= nFileEnd) // 安全性檢測
{
cout<<"沒有找到合法的幀"<<endl;
file.close();
exit(0);
}
// 看當前字符是不是0xaa,如果不是,則重新尋找7個連續的0xaa
if (file.get() != 0xaa)
{
j = -1;
}
}
if (file.tellg() >= nFileEnd) // 安全性檢測
{
cout<<"沒有找到合法的幀"<<endl;
file.close();
exit(0);
}
if (file.get() == 0xab) // 判斷7個連續的0xaa之后是否為0xab
{
break;
}
}
// 將數據字段偏移量定位在上述二進制串之后14字節處,并準備進入解析階段
nCurrDataOffset = file.tellg() + 14;
file.seekg(-8,ios::cur);
// 主控循環
while ( bParseCont ) // 當仍然可以繼續解析輸入文件時,繼續解析
{
// 檢測剩余文件是否可能包含完整幀頭
if (file.tellg() + 14 > nFileEnd)
{
cout<<endl<<"沒有找到完整幀頭,解析終止"<<endl;
file.close();
exit(0);
}
int c; // 讀入字節
int i = 0; // 循環控制變量
int EtherType = 0; // 由幀中讀出的類型字段
bool bAccept = true; // 是否接受該幀
// 輸出幀的序號
cout << endl << "序號:\t\t" << nSN;
// 輸出前導碼,只輸出,不校驗
cout << endl << "前導碼:\t";
for (i = 0; i < 7; i++) // 輸出格式為:AA AA AA AA AA AA AA
{
cout.width(2);
cout << hex << file.get() << dec << " ";
}
// 輸出幀前定界符,只輸出,不校驗
cout << endl << "幀前定界符:\t";
cout.width(2); // 輸出格式為:AB
cout << hex << file.get();
// 輸出目的地址,并校驗
cout << endl << "目的地址:\t";
for (i = 0; i < 6; i++) // 輸出格式為:xx-xx-xx-xx-xx-xx
{
c = file.get();
cout.width(2);
cout<< hex << c << dec << (i==5 ? "" : "-");
if (i == 0) // 第一個字節,作為“余數”等待下一個bit
{
nCheck = c;
}
else // 開始校驗
{
checkCRC(nCheck, c);
}
}
// 輸出源地址,并校驗
cout << endl << "源地址:\t";
for (i = 0; i < 6; i++) // 輸出格式為:xx-xx-xx-xx-xx-xx
{
c = file.get();
cout.width(2);
cout<< hex << c << dec << (i==5 ? "" : "-");
checkCRC(nCheck, c); // 繼續校驗
}
// 輸出類型字段,并校驗
cout<<endl<<"類型字段:\t";
cout.width(2);
// 輸出類型字段的高8位
c = file.get();
cout<< hex << c << dec << " ";
checkCRC(nCheck, c); // CRC校驗
EtherType = c;
// 輸出類型字段的低8位
c = file.get();
cout.width(2);
cout<< hex << c;
checkCRC(nCheck,c); // CRC校驗
EtherType <<= 8; // 轉換成主機格式
EtherType |= c;
// 定位下一個幀,以確定當前幀的結束位置
while ( bParseCont )
{
for (int i = 0; i < 7; i++) //找下一個連續的7個0xaa
{
if (file.tellg() >= nFileEnd) //到文件末尾,退出循環
{
bParseCont = false;
break;
}
// 看當前字符是不是0xaa,如果不是,則重新尋找7個連續的0xaa
if (file.get() != 0xaa)
{
i = -1;
}
}
// 如果直到文件結束仍沒找到上述比特串,將終止主控循環的標記bParseCont置為true
bParseCont = bParseCont && (file.tellg() < nFileEnd);
// 判斷7個連續的0xaa之后是否為0xab
if (bParseCont && file.get() == 0xab)
{
break;
}
}
// 計算數據字段的長度
nCurrDataLength =
bParseCont ? // 是否到達文件末尾
(file.tellg() - 8 - 1 - nCurrDataOffset) : // 沒到文件末尾:下一幀頭位置 - 前導碼和定界符長度 - CRC校驗碼長度 - 數據字段起始位置
(file.tellg() - 1 - nCurrDataOffset); // 已到達文件末尾:文件末尾位置 - CRC校驗碼長度 - 數據字段起始位置
// 以文本格式數據字段,并校驗
cout << endl << "數據字段:\t";
unsigned char* pData = new unsigned char[nCurrDataLength]; // 創建緩沖區
file.seekg(bParseCont ? (-8 - 1 -nCurrDataLength) : ( -1 - nCurrDataLength), ios::cur);
file.read(pData, nCurrDataLength); // 讀入數據字段
int nCount = 50; // 每行的基本字符數量
for (i = 0; i < nCurrDataLength; i++) // 輸出數據字段文本
{
nCount--;
cout << pData[i]; // 字符輸出
checkCRC(nCheck, (int)pData[i]); // CRC校驗
if ( nCount < 0) // 換行處理
{
// 將行尾的單詞寫完整
if ( pData[i] == ' ' )
{
cout << endl << "\t\t";
nCount = 50;
}
// 處理過長的行尾單詞:換行并使用連字符
if ( nCount < -10)
{
cout<< "-" << endl << "\t\t";
nCount = 50;
}
}
}
delete[] pData; //釋放緩沖區空間
// 輸出CRC校驗碼,如果CRC校驗有誤,則輸出正確的CRC校驗碼
cout << endl <<"CRC校驗";
c = file.get(); // 讀入CRC校驗碼
int nTmpCRC = nCheck;
checkCRC(nCheck, c); // 最后一步校驗
if ((nCheck & 0xff) == 0) // CRC校驗無誤
{
cout.width(2);
cout<<"(正確):\t"<< hex << c;
}
else // CRC校驗有誤
{
cout.width(2);
cout<< "(錯誤):\t" << hex << c;
checkCRC(nTmpCRC, 0); // 計算正確的CRC校驗碼
cout<< "\t應為:" << hex << (nTmpCRC & 0xff);
bAccept = false; // 將幀的接收標記置為false
}
// 如果數據字段長度不足46字節或數據字段長度超過1500字節,則將幀的接收標記置為false
if (nCurrDataLength < 46 || nCurrDataLength > 1500 )
{
bAccept = false;
}
// 輸出幀的接收狀態
cout<< endl << "狀態:\t\t" << (bAccept ? "Accept" : "Discard") << endl <<endl;
nSN++; // 幀序號加1
nCurrDataOffset = file.tellg() + 22; // 將數據字段偏移量更新為下一幀的幀頭結束位置
}
// 關閉輸入文件
file.close();
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -