//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(®ex,pattern,REG_EXTENDED);
if(state){
char* errbuf = calloc(50,sizeof(char));
regerror(state,®ex,errbuf,50);
fprintf(stderr,"Regex: %s compile failed.\nReason: %s\n",pattern,errbuf);
free(errbuf);
exit(EXIT_FAILURE);
}
regmatch_t matches[2];
state = regexec(®ex,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(®ex,p1,REG_EXTENDED);
if(state){
char* errbuf = calloc(50,sizeof(char));
regerror(state,®ex,errbuf,50);
fprintf(stderr,"Regex:%s compile failed.\nReason:%s\n",p1,errbuf);
free(errbuf);
exit(EXIT_FAILURE);
}
state = regexec(®ex,data,0,NULL,0);
if(state == REG_NOMATCH){
fprintf(stderr,"Data: %s invalid!\n",data);
return false;
}
regfree(®ex);
state = regcomp(®ex,p2,REG_EXTENDED);
if(state){
char* errbuf = calloc(50,sizeof(char));
regerror(state,®ex,errbuf,50);
fprintf(stderr,"Regex: %s compile failed.\nReason:%s\n",p2,errbuf);
free(errbuf);
exit(EXIT_FAILURE);
}
state = regexec(®ex,g,0,NULL,0);
regfree(®ex);
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].