zfec源碼解析與實例解析

   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,         /*生成的校驗數據的指針*/
   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。


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 在初始位置的索引。


寫自己的代碼的時候需要把源碼中的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;
  
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章