Ошибка zlib inflate: Z_DATA_ERROR, когда полученные пакеты вышли из строя или потеряны - PullRequest
1 голос
/ 26 марта 2020

У меня есть работа в течение нескольких недель, очень надеюсь на вашу помощь !!! пожалуйста, прости мой бедный английский sh.

Во-первых, я думаю, что необходимо описать сценарий приложения:

  1. какие данные я хочу распаковать? ---- данные поступают из сетевого трафика c целого числа rnet. В этих трафиках c некоторые данные сжимаются gzip и сохраняются в пакете http или tcp. Если размер данных огромен и превышает максимальную длину полезной нагрузки tcp, он будет разрезан и передан. Я могу извлечь сжатые данные из этих пакетов и сгруппировать эти данные по потоку TCP. поэтому я могу заверить, что данные, извлеченные из этих пакетов одного указанного потока c, принадлежат одному источнику данных. поэтому данные состоят из множества блоков сжатых данных, сценарий приложения требует, чтобы вы распаковывали данные сразу после получения одного пакета. Для каждого потока tcp мы поддерживаем структуру данных z_stream.
  2. Когда программа сообщает об ошибке? ---- Вся ошибка: «Z_DATA_ERROR: недопустимое расстояние слишком далеко назад». тогда я нахожу, когда полученный пакет вышел из строя или какой-то пакет потерян , ошибка произойдет!

Один простой случай:

Сжатые данные разбиваются на несколько блоков данных и сохраняются в сетевых пакетах данных (p1, p2, p3 , p4, p5, p6, p7), а затем передать в одном указанном c TCP-потоке. Для каждого потока tcp мы поддерживаем структуру данных z_stream. Очевидно, что p1 включает заголовок gzip 0x1f 0x8b 0x08 ...), но из-за неопределенности в сетевой передаче полученный пакет может быть не в порядке или потеря , например: (p1, p2, p5, p6, p7, p3, p4), первые два пакета могут нормально декомпрессироваться, но при декомпрессии p5 возникает ошибка (Z_DATA_ERROR).

ТАК, у меня есть следующие проблемы:

  1. Из-за сценария приложения мне нужно распаковать данные после получения одного пакета с gzip-кодированием содержимого. Итак, я хочу знать, поддерживает ли zlib такую ​​функцию ---- напрямую распаковывать сжатый блок без учета порядка поступления пакетов?
  2. Я также проверяю влияние порядка получения пакетов : Если я отсортирую данные в исходном порядке, а затем последовательно распакую их, они будут распакованы нормально.
  3. В-третьих, логически говоря, для пакетного полученного заказа (p1, p2, p5, p6, p7, p3, p4), при последовательной распаковке этих пакетов, p1, p2 будет успешно распаковываться, p5, p6, p7 распаковка не удалась, следующий полученный пакет - p3. Логически говоря, он должен быть успешно распакован, но когда я проверяю этот случай, он не удался, я не понимаю этого.
  4. Я также нашел сбивающая с толку проблема, которая не часто случается: если я сортирую пакет как (p1, p2, p3, p5, p4 ...), логически говоря, когда декомпрессировать p5, он должен сообщить об ошибке, если он распаковывается успешно, я не понимаю этого.

    следующий исходный код:


/**
 * buf: the gzip compressed data that extract form tcp packet
 */
void dowithGzipDataByZlib(z_stream * p_zlib_strm, unsigned char * buf, int buflen)
{
    int zlib_status = Z_OK;
    int bytes_dc_now = 0;
    unsigned char pNowResBuff[4096];
    printf("-------\n");
    (*p_zlib_strm).avail_in = buflen;
    (*p_zlib_strm).next_in = buf;
    do {
        memset(pNowResBuff,0,4096);
        (*p_zlib_strm).avail_out = 4096;
        (*p_zlib_strm).next_out = pNowResBuff;
        zlib_status = inflate (p_zlib_strm, Z_NO_FLUSH);
        printf("inflate status:%d\n",zlib_status);
        if(Z_OK != zlib_status && Z_STREAM_END!=zlib_status){
            printf("(*p_zlib_strm).avail_in:%d\n",(*p_zlib_strm).avail_in);
            printf("err msg:%s\n",p_zlib_strm->msg);
            return ;
        }
        bytes_dc_now = 4096 - (*p_zlib_strm).avail_out;
        // printf("bytes_dc_no:")
    } while(0 == (*p_zlib_strm).avail_out) ; 

    printf("(*p_zlib_strm).avail_in:%d\n",(*p_zlib_strm).avail_in);
}

// under the dirpath, there are some compressed data extract from the packets of one specific tcp stream, and store them in "file_basename_%d" file. (%d is the recieve order num: 1,2,3,4...)
void read( char* dirpath, char* file_basename)
{
    char filelist[99][255];
    int file_count = listDir(dirpath, filelist, 99, 255);
    char filepath[255];

    z_stream zlib_strm = {0};
    zlib_strm.zalloc = Z_NULL;
    zlib_strm.zfree = Z_NULL;
    zlib_strm.opaque = Z_NULL;
    zlib_strm.next_in = Z_NULL;
    zlib_strm.avail_in = 0;
    inflateInit2 (& zlib_strm, 32 | MAX_WBITS);

    FILE* fp;
    char buf[2048];

    // sort_file_ind: the array store the origin order of the compressed data.
    int sort_file_ind[99] = {0,1,2,3,15,16,17,18,19,20,21,4,5,6,7,8,9,10,11,12,13,14};

    for(int i=1;i<=file_count-2;i++)
    {
        memset(filepath,0,sizeof(filepath));
        // snprintf(filepath,sizeof(filepath), "%s%s%d",dirpath,file_basename,sort_file_ind[i]);
        snprintf(filepath,sizeof(filepath), "%s%s%d",dirpath,file_basename,i);
        printf("%s\n",filepath);
        fp = fopen(filepath,"r");
        if(fp == NULL){

            return;
        }
        fseek(fp, 0, SEEK_END);
        int flen = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        memset(buf,0,sizeof(buf));
        int dlen = fread(buf, 1, flen, fp);
        if(dlen != flen){
            fclose(fp);
            return;
        }
        printf("dlen:%d\n",dlen);
        dowithGzipDataByZlib(&zlib_strm,(unsigned char *)buf,dlen);
        fclose(fp);
    }
}


char * dir = "/data/GzipDC/softDC/DocumentAnalyze/testbyzs/data/119.40.37.65.42050/";
char * base_filename = "119.40.37.65.42050>180.76.22.49.80_1_";

int main()
{
    read(dir,base_filename);
    return 0;
}

Я много раз спрашивал и много раз пробовал, и мне действительно нужен кто-то с знания по теме, чтобы взвесить здесь. Спасибо за ваше время!

...