zfec源码解析与实例解析

时间:2022-12-17 19:36:28

   zfec是一种前向纠删码,用于给原始数据增加冗余信息,以提高数据的安全性。zfec提供了诸如c、python等语言的接口。在这里只介绍有关c语言的接口。(这篇文章主要是参考学习博客http://www.dullgull.com/2012/07/zfec-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/,但是代码部分是原创的并且保证是正确的)

   zfec源代码的下载地址为:http://pypi.python.org/pypi/zfec


1、fec_t :这是一个结构,通过fec_new() 返回可以得到,不用自己初始化。fec->k 是数据块的数目,fec->n 是所有块总数(数据块+校验块)
2、fec_new():初始化,生成fec_t 结构,并给定了k,m(需要重建数据块数,总数据块数)
3、fec_free():释放初始化的空间
4、fec_encode():编码 (具体参数如下)
5、fec_decode():解码 (具体参数如下)
 
1、fec_t结构:
   1: typedef struct {    
   2:     unsigned long magic;    
   3:     unsigned short k, n;     /* parameters of the code */    
   4:     gf* enc_matrix;        //其中的k是数据块的个数,n是所有块的总数(包括数据块和校验块)
   5: } fec_t;
 
2、fec_new()
   1: fec_t* fec_new(
   2:     unsigned short k,     /*原数据块个数,对应编码理论中k */
   3:     unsigned short m      /*编码后所有数据块个数,对应编码理论中n */
   4: )
 
3、fec_free()
   1: void fec_free(
   2: fec_t* p
   3: )
 
4、fec_encode()
   1: void fec_encode(
   2:     const fec_t* code, /*fec_t 结构的指针*/
   3:     const gf*restrict const*restrict const src, /*原始数据指针*/
   4:     gf*restrict const*restrict const fecs, /*fec 生成的校验数据的指针*/
   5:     const unsigned*restrict const block_nums, 
   6:     /*记录冗余数据块在整个数据(包含原始数据)中的索引数组*/
   7:     size_t num_block_nums, /*冗余数组的大小*/
   8:     size_t sz /*每个数据块的大小*/
   9: ) 
src[0] 到src[ECC_K-1] 是指向第0 个到第ECC_K-1 个数据块的指针;(分别指向D1-D5)
fecs[0] 到fecs[ECC_C-1] 是指向第0 个到第ECC_C-1 个校验块的指针;(需要预先分配好校验块的空间,分别指向C1-C3)
blocks_nums 是校验块索引数组的指针,blocks_nums 指向的空间也应该提前分配好,是一个ECC_C 大小的空间,保存从ECC_K,…,ECC_N-1。(对应下图,索引数组保存5、6、7 )
num_block_nums 是上面blocks_nums 指向空间的大小,也就是校验块个数:ECC_C = ECC_N – ECC_K。

zfec源码解析与实例解析

5、fec_decode()
   1: void fec_decode( 
   2:     const fec_t* code, /*fec_t 结构的指针*/
   3:     const gf*restrict const*restrict const inpkts, 
   4:     /*用来恢复丢失数据的数据数组,其内的指针必须按编码前的顺序升序存放,如果丢包则拿冗余块补入,
   5:       其中冗余块必须放在丢失数据块的位置。指针所指数组大小为k*/
   6:     gf*restrict const*restrict const outpkts, 
   7:     /*存放找回的数据块,所指数组大小为丢失块数量*/
   8:     const unsigned*restrict const index, 
   9:     /*传入的数据包的序号,数组大小为k,对应inpkts中每个数据块在全部数据块中的索引*/
  10:     size_t sz 
  11: ) 
inpkts 是恢复数据块和校验块指针,需要注意的是数据块应该按照其原来的位置放置,缺少数据块的部分用校验块填充,不可以按照数据块校验块顺序放置,否则会解码错误
outpkts 是恢复出来的数据块的指针,也要预先分配空间
index 是用于恢复的数据块与校验块对应在inpkts 里面的索引。
如下图D1/D4/C2 块发生损坏,那么重建的数据块由D2/D3/D5/C1/C3。那么inpkts 指针应该有这样关系:
inpkts->C1(校验块的位置只需和后面index 索引对齐即可)
inpkts+1->D2 (数据块应该保持其原来位置)
inpkts+2->D3(数据块应该保持其原来位置)
inpkts+3->C3(校验块的位置只需和后面index 索引对齐即可)
inpkts+4->D5(数据块应该保持其原来位置)
那么对应index 指向的数组应该为[5,1,2,7,4] ,对应的也就是C1/D2/D3/C3/D5 在初始位置的索引。

zfec源码解析与实例解析
写自己的代码的时候需要把源码中的fec.c文件编译成fec.o编译方法如下:gcc -c fec.c -std=c99 然后再和自己写的程序一起进行编译连接。比如你写的程序是test.c ,则这个时候编译成可执行的文件test的方法是:gcc test.c fec.o -o test -std=c99这样就生成了可执行的文件test了。  以下是自己写的一段简单的encode和decode的代码,主要是对指定的字符串进行编码和解码: #include<stdlib.h>
#include<stdio.h>
#include "fec.h"
#define ECC_K 4
#define ECC_N 8
#define ECC_C (ECC_N-ECC_K)
#define BLK_SZ (24/ECC_K)
int main(int argv,char *argc[])
{  
    fec_t *code;
    char *src[ECC_K];//用来存放数据块的数据
    char *fecs[ECC_C];//校验数据的指针
    char cdata[25]={0};
    unsigned blocks[ECC_C];//用来存放校验块在整个数据中的索引
    int i=0;
    char data[]="abcdefetefetasetfgerder!";
    int index[ECC_K]={4,5,6,7};
    char *in_recovery[ECC_K];
    char *out_recovery[ECC_K];
    char buf_recovery[ECC_K*BLK_SZ+1];//
    code=fec_new(ECC_K,ECC_N);
    for(i=0;i<ECC_K;i++)
    {//初始化数据块数据
         src[i]=data+BLK_SZ*i;//这里是存储的是六个数据节点中的数据,就是相当于把data的数据分散到了六个数据节点上面。然后src【i】各存一个数据节点中的数据
    }

    for(i=0;i<ECC_C;i++)
    {//初始化校验块
       blocks[i]=ECC_K+i;
       fecs[i]=cdata+i*BLK_SZ;
    }
    
    printf("the src is %s\n",*src);
    printf("the cdata is:%s\n",cdata);
    printf("the src is: %s\n",*fecs);
   for(i=0;i<ECC_C;i++)
    {//这是整数
      printf("the blocks is:%d\n",blocks[i]);
    }
    fec_encode(code,src,fecs,blocks,ECC_C,BLK_SZ);
   printf("the encode is end!\n");   
    printf("the src is %s\n",*src);


   for(i=0;i<ECC_K;i++)
   {//这种情况就是在四个数据块都出现错误的时候的进行的恢复
      in_recovery[i]=fecs[i];
      out_recovery[i]=buf_recovery+i*BLK_SZ;
   } 


  fec_decode(code,in_recovery,out_recovery,index,BLK_SZ);
  buf_recovery[ECC_K*BLK_SZ]='\0';

  printf("Recovery is :%s\n",buf_recovery);
//注意这里的buf_recovery的内容是出现错误的数据块的数据,在这里是D1、D2、D3、D4的数据
//以下验证的是D1、D4、C1、C2四个块出错然后进行恢复的代码
 printf("the second deconde!\n");
/*  index[0]=6;
  index[1]=1;
  index[2]=2;
  index[3]=7;
  memset(buf_recovery,0,sizeof(buf_recovery));
  in_recovery[0] = fecs[2];
  in_recovery[1] = data+1*BLK_SZ;
  in_recovery[2] = data+2*BLK_SZ;
  in_recovery[3] = fecs[3];
*/

//以下验证的是D2、D3、C1、C2四个块出错然后进行恢复的代码
//其中恢复的结果是恢复出错的块的数据
  index[0]=0;
  index[1]=6;
  index[2]=7;
  index[3]=3;
  memset(buf_recovery,0,sizeof(buf_recovery));
  in_recovery[0] = data+0*BLK_SZ;
  in_recovery[1] = fecs[2];
  in_recovery[2] = fecs[3];
  in_recovery[3] = data+3*BLK_SZ;
  for(i = 0 ; i < ECC_K ; i++)
  {//其中buf_recovery中存放的是出现错误的数据块的数据,在这里是D2、D3的数据
      out_recovery[i] = buf_recovery + i*BLK_SZ;
  }
  fec_decode(code, in_recovery, out_recovery, index, BLK_SZ);
  buf_recovery[ECC_K*BLK_SZ] = '\0';
  printf("Recovery is :%s\n",buf_recovery);
   //printf("the k=%d and n=%d ",code->k,code->n);
return 0;
  
}