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;
	
}

总的说来,这个程序还是有很多很多需要修改的地方,健壮性很差,等有时间再好好完善一下.



  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值