数据链路层 差错控制 循环冗余检验 CRC循环冗余码计算 Redundancy PDU - data link

//Redundancy PDU - data link 
//数据链路层 差错控制-检错编码:循环冗余检验 原理代码
//冗余检验主要是通过设定 预定多项式G(x),并且发送端在原始IP分组比特末端添加预定多项式长度少 - 1个值为0的比特
//通过对预定多项式循环冗余(异或)处理,得到检错编码并添加到原始IP分组末端后发送到接收方
//当接收方数据链路层接收到数据后通过对数据进行与之相应的预定多项式G(x)进行冗余(异或)计算.
//当对应结果为0是则数据无误.
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <regex.h>
#include <stdio.h>
#include <assert.h>
#include <time.h>

typedef int errno_t;

//functions prototype
//FCS 生成n位冗余码
char* FCS(char* data,char* g);
//判断输入有效性
bool validData(char* data,char* g);
//截取data中的有效部分
char* reduce(char* data,char* g);
//检测接受到数据有效性
bool CRC(char* data,char* g);
/*
 *  data: 原始IP数据报分组PDU + 末端补预定多项式G(x)长度- 1个0的比特
 *  g:    预定多项式G(x): eg: 1101 
 *        多项式G(x)的阶为3
 */

int main(void){
	char* data = calloc(31,sizeof(char));
	char* g = calloc(7,sizeof(char));
	data:
	printf("Enter the IP Data Datagram(PDU)[max:30]: ");
	scanf("%s",data);
	g:
	printf("Enter G(x)[max:6]:");
	scanf("%s",g);
	bool valid = validData(data,g);
	if(!valid){
		exit(EXIT_FAILURE);
	}
	if(strlen(data) > 30 || strlen(data) == 0){
		fprintf(stderr,"data invalid.[max:30,min:1,current: %zd]\n>",strlen(data));
		goto data;
	}
	if(strlen(g) > 6){
		fprintf(stderr,"g invalid.[max:6,current: %zd]\n>",strlen(g));
		goto g;
	}
	
	char* testData = calloc(strlen(data) + strlen(g),sizeof(char));
	memset(testData,'0',strlen(data) + strlen(g) - 1);
	memcpy(testData,data,strlen(data));
	
	printf("\nSender>           data:%s\n",data);//发送方原始数据
	printf("Sender>       testData:%s\n",testData);//发送方计算数据
	
	char* tail = FCS(testData,g);
	
	
	printf("Sender>            FCS:%s\n",tail);
	char* sendData = calloc(strlen(data) + strlen(g),sizeof(char));
	memcpy(sendData,data,strlen(data));
	memcpy(sendData + strlen(sendData),tail,strlen(tail));
	printf("Sender>      send data:%s\n",sendData);//发送方发送数据
	
//以下可对sendData进行错误数值赋值检测结果 
#define INCORRECT	
#undef INCORRECT

#if defined INCORRECT	
	
	srand(time(NULL));
	int index = rand() % strlen(sendData);
	sendData[index] = (sendData[index] == '1' ? '0' : '1');
	fprintf(stderr,"\n\n[Incorrect data test]");
#else
    printf("\n\n[correct data test]");
#endif	
	
	printf("\nReceiver> receive data:%s\n",sendData);//接收方接收数据
	valid = CRC(sendData,g);
	printf("Receiver> check result FCS[%s] : %s\n",FCS(sendData,g),valid ? "[valid]" : "[invalid].");//接收方循环冗余检验
	//接收方冗余检验后如果结果为预定多项式G(x)长度-1个0的比特位,则校验无误.
	
	free(data);
	free(g);
	free(testData);	
	free(sendData);
	
	return 0;
}

bool CRC(char* data,char* g){
	char* fcs = FCS(data,g);
	for(int i = 0 ; i < strlen(g) - 1 ; i ++){
		if(fcs[i] != '0'){
			return false;
		}
	}
	return true;
}

char* FCS(char* data,char* g){
	int len = strlen(g);
	retry:
	
	for(int i = 0 ; i < len ; i ++){
		if(data[i] != g[i]){
			data[i] = '1';
		}else{
			data[i] = '0';
		}
	}
	data = reduce(data,g);
	if(strlen(data) != strlen(g) - 1){
		goto retry;
	}
	return data;
}

char* reduce(char* data,char* g){
	/*
	 * 此函数用于缩减data.(注意这里的data是在原始IP分组尾部补充 预定多项式长度-1个值为0的比特后的数据)
	 * 主要实现功能是去除首部的0比特[由于当data首位为0时,那么除数就商0.相当于除去首部所有0比特位]
	 * 1.当截取后的剩余长度小于 预定多项式G(x)长度 -1 时候则前部比特值补0
	 * 2.当截取后生于长度大于 预定多项式G(x)长度 -1 时候则直接返回对应比特内容
	 */ 
	char* reval = NULL;
	regex_t regex;
	char* pattern = "^0*(.*)$";
	errno_t state = regcomp(&regex,pattern,REG_EXTENDED);
	if(state){
		char* errbuf = calloc(50,sizeof(char));
		regerror(state,&regex,errbuf,50);
		fprintf(stderr,"Regex: %s compile failed.\nReason: %s\n",pattern,errbuf);
		free(errbuf);
		exit(EXIT_FAILURE);
	}
	regmatch_t matches[2];
	state = regexec(&regex,data,2,matches,0);
	assert(state == 0);
	int len = matches[1].rm_eo - matches[1].rm_so;
	if(len < strlen(g)){
		reval = calloc(strlen(g),sizeof(char));
		memset(reval,'0',strlen(g) - 1);
		memcpy(reval + (strlen(g) - 1 - len),data + matches[1].rm_so,len);
		return reval;
	}
	
	reval = calloc(len + 1,sizeof(char));
	memcpy(reval,data + matches[1].rm_so,len);
	return reval;
}

bool validData(char* data,char* g){
	/*有效性检测.
	 * 1.对于PDU字符串,仅仅只能包含 1 或 0
	 * 2.对于预定多项式G(x),仅能包含 1 或 0.并且首尾必须都是 1
	 */
	regex_t regex;
	char* p1 = "^[01]+$";
	char* p2 = "^1[01]*1$";
	
	errno_t state = regcomp(&regex,p1,REG_EXTENDED);
	if(state){
		char* errbuf = calloc(50,sizeof(char));
		regerror(state,&regex,errbuf,50);
		fprintf(stderr,"Regex:%s compile failed.\nReason:%s\n",p1,errbuf);
		free(errbuf);
		exit(EXIT_FAILURE);
	}
	
	state = regexec(&regex,data,0,NULL,0);
	if(state == REG_NOMATCH){
		fprintf(stderr,"Data: %s invalid!\n",data);
		return false;
	}
	
	regfree(&regex);
	
	state = regcomp(&regex,p2,REG_EXTENDED);
	if(state){
		char* errbuf = calloc(50,sizeof(char));
		regerror(state,&regex,errbuf,50);
		fprintf(stderr,"Regex: %s compile failed.\nReason:%s\n",p2,errbuf);
		free(errbuf);
		exit(EXIT_FAILURE);
	}
	state = regexec(&regex,g,0,NULL,0);
	regfree(&regex);
	if(state == REG_NOMATCH){
		fprintf(stderr,"G(x) %s invalid!\n",g);
		return false;
	}
	
	return true;
}





第72行代码 #undef INCORRECT 作为修改帧内容开关. (注释后产生错误结果)


Enter the IP Data Datagram(PDU)[max:30]: 101001010111
Enter G(x)[max:6]:101101

Sender>           data:101001010111
Sender>       testData:10100101011100000
Sender>            FCS:11111
Sender>      send data:10100101011111111


[correct data test]
Receiver> receive data:10100101011111111
Receiver> check result FCS[00000] : [valid]
 


Enter the IP Data Datagram(PDU)[max:30]: 101001010111
Enter G(x)[max:6]:101101

Sender>           data:101001010111
Sender>       testData:10100101011100000
Sender>            FCS:11111
Sender>      send data:10100101011111111


[Incorrect data test]
Receiver> receive data:10100101011111101        此处帧内容已被修改.接收方检测数据有误.
Receiver> check result FCS[00010] : [invalid].
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值