1. 程式人生 > >C語言實現MAC幀的封裝與解封裝

C語言實現MAC幀的封裝與解封裝

這周做計算機網路課程設計,在幾個題目中選了個MAC幀的封裝.

首先看最後結果:



這裡有個bug,不知道為什麼幀前導碼和幀定界符前多了FFFFFF,我自己沒搞懂???

程式如下:

/*
目標:
封裝
1.將inputFile檔案中的資料封裝成MAC幀,封裝好的MAC幀寫入outputFile檔案中.
2.如果資料長度小於46位元組,則補全到46位元組
3.如果資料長度大於1500,則封裝成多個MAC幀
解封裝:
讀取outputFile中的資料,並逐個顯示幀的資訊

其實我們要求還是蠻低的,上面有好多是自己新增的
*/
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 1500
#define echo(format,str) printf("%"#format,str)
#define inputFile "inputFile.txt" 
#define outputFile "outputFile.txt" 
void flush()
{
	fflush(stdin);
	fflush(stdout);
}


unsigned int  crc8(unsigned char *ptr,unsigned  int len)
/*
CRC校驗,ptr是需要計算的陣列首地址,len是需要計算的長度
*/
{
    unsigned int  CRC = 0;
    unsigned int  i;
	
    while(len--){
        CRC = CRC^ *ptr++;
        for(i = 0; i < 8; i++){
            if(CRC & 0x01){
                CRC = (CRC >> 1 )^ 0x8c;
            }
			else{
				CRC >>= 1;
			}
        }                   
    }
	
    return CRC;  
}


int encapsulation()
/*幀封裝函式*/
{
	int i,dataCrc,nu,j,lastNu,sum;
	FILE *fpIn,*fpOut;
	int src[6],des[6];
	char type[2],data[MAXSIZE];
	if((fpIn=fopen(inputFile,"a+"))==NULL)
	{
		echo(s,"開啟檔案失敗!");
		return 1;
	}
	if((fpOut=fopen(outputFile,"wb"))==NULL)
	{
		echo(s,"寫入檔案失敗");
		return 1;
	}

	fseek(fpIn,0,SEEK_END);
	sum=ftell(fpIn);
	nu=sum/1500;
	if((sum-nu*1500)<46)
	{
		for(i=0;i<(46-(sum-nu*1500));i++)
			fputc(0x0,fpIn);   //如果不足,則填充
	}

	rewind(fpIn);

	echo(s,"請輸源MAC:");
	scanf("%x-%x-%x-%x-%x-%x",src,src+1,src+2,src+3,src+4,src+5);
	fflush(stdin);
	echo(s,"請輸入目標MAC:");
	scanf("%x-%x-%x-%x-%x-%x",des,des+1,des+2,des+3,des+4,des+5);
	flush();
	echo(s,"請輸入型別欄位:");
	flush();
	scanf("%2x%2x",type,type+1);

	for(j=0;j<nu+1;j++)
	{
		for(i=0;i<7;i++)
			fputc(0xaa,fpOut);   //寫入幀前導碼
		fputc(0xab,fpOut);       //寫入幀定界符

		for(i=0;i<6;i++)
		{
			fputc(des[i],fpOut);    //寫入目的MAC
		}
		for(i=0;i<6;i++)
		{
			fputc(src[i],fpOut);   //寫入源MAC
		}
		
		fputc(type[0],fpOut);     //寫入型別號
		fputc(type[1],fpOut);


		if(j!=nu)
		/*不是最後一個數據,則前面的資料都應該是1500*/
		{
			fread(data,sizeof(char),1500,fpIn);
			fwrite(data,sizeof(char),1500,fpOut);
			dataCrc=crc8(data,1500);
			fputc(dataCrc,fpOut);
		}
		else
		{
			//最後一段資料,需要額外處理,獲取長度
			lastNu=ftell(fpIn);
			fread(data,sizeof(char),sum-lastNu,fpIn);
			fwrite(data,sizeof(char),sum-lastNu,fpOut);
			dataCrc=crc8(data,sum-lastNu);
			fputc(dataCrc,fpOut);
		}
	}
	
	fclose(fpIn);
	fclose(fpOut);

	echo(s,"\n\n");

	return 0;
}


int unPack()
/*解封裝函式*/
{	
	int i,dataStart,dataEnd,srcCrc,nowCrc,dataLength,frameNu=0,sum,j;
	char c,data[MAXSIZE];
	FILE *fpOut;
	if((fpOut=fopen(outputFile,"rb"))==NULL)
	{
		echo(s,"開啟檔案失敗!");
		return 1;
	}

	fseek(fpOut,0,SEEK_END);
	sum=ftell(fpOut);
	rewind(fpOut);

	while(1)
		/*此迴圈為了獲取幀的個數
		主要思路:連續7個0xaa,第8個是0xab
		*/
	{
		if(ftell(fpOut)>=sum)
		{
			break;
		}
		for(i=0;i<7;i++)
		{
			if(ftell(fpOut)>=sum)
			{
				break;
			}

			if(fgetc(fpOut)!=0xaa)
			{
				i=-1;
			}
		}
		if(ftell(fpOut)>=sum)
		{
			break;
		}
		if(fgetc(fpOut)==0xab)
		{
			++frameNu;
		}
	}
	rewind(fpOut);

	for(j=0;j<frameNu;j++)
		/*迴圈逐個輸出幀的資訊*/
	{
		printf("\n\n幀序號: %d\n\n",j+1);
		echo(s,"幀前導碼: ");
		for (i=0;i<7;i++)
		{
			c=fgetc(fpOut);
			echo(.2X,c);
		}
		echo(s,"\n\n");

		echo(s,"幀前定界符: ");
		{
			c=fgetc(fpOut);
			echo(.2X,c);
		}

		echo(s,"\n\n");

		echo(s,"目的MAC地址: ");
		for (i=0;i<6;i++)
		{
			c=fgetc(fpOut);
			echo(.2X,c);
			if (i!=5)
				echo(s,"-");	
		}
		echo(s,"\n\n");	

		echo(s,"源MAC地址: ");
		for (i=0;i<6;i++)
		{
			c=fgetc(fpOut);
			echo(.2X,c);
			if (i!=5)
				echo(s,"-");	
		}
		echo(s,"\n\n");

		echo(s,"型別號: ");

		c=fgetc(fpOut);
		echo(.2X,c);
		c=fgetc(fpOut);
		echo(.2X,c);

		if(j!=frameNu-1)
			//不是最後一個幀,則資料長度都是1500
		{
			fread(data,sizeof(char),1500,fpOut);
			srcCrc=fgetc(fpOut);
			nowCrc=crc8(data,1500);
		}
		else
		{
			//最後一個幀,額外處理
			dataStart=ftell(fpOut);
			fseek(fpOut,-1,SEEK_END);
			dataEnd=ftell(fpOut)-1;
			dataLength=dataEnd-dataStart+1;
			srcCrc=fgetc(fpOut);
			fseek(fpOut,dataStart,SEEK_SET);
			fread(data,sizeof(char),dataLength,fpOut);
			nowCrc=crc8(data,dataLength);
		}

		printf("\n\n本次CRC:  %d",nowCrc);
		echo(s,"\n\n行為: ");
		if (nowCrc==srcCrc) //比較CRC,是否出錯
			echo(s,"接受");
		else
			echo(s,"丟棄");
			printf("  前次CRC:%d",srcCrc);
	
	}
	fclose(fpOut);
	echo(s,"\n\n");
	return 0;
}
void choice()
{
	int choice;
	echo(s,"1.幀封裝\n");
	echo(s,"2.幀解析\n");
	echo(s,"3.退出\n");
	echo(s,"\t請選擇序號:");
	scanf("%d",&choice);
	switch(choice)
	{
	case 1:
		encapsulation();
		break;
	case 2:
		unPack();
		break;
	case 3:
		echo(s,"歡迎使用....\n");
		exit(0);
	default:
		putchar('\a');
		echo(s,"序號在1-3,請重新選擇\n");
			
	}
}
int main(int argc,char **argv)
{
	while(1)
	{
		
		choice();
		echo(s,"\n");
	}
	return 0;
	
}

總的說來,這個程式還是有很多很多需要修改的地方,健壯性很差,等有時間再好好完善一下.