2017-01-25 20 views
0

私は時間が経つにつれて成長するバッファ(文字列)を持っており、入力サイズが制限されたチャネル(4096バイト)でこのバッファを送信する必要があります。このチャネルを介した通信はコストがかかるため、圧縮されたデータを送信する方が良い理由です。バッファの成長は、異なるサイズのブロックによって行われます。これらのブロックは分割できないか、意味が失われます。成長バッファ(C++、zlib)の累積圧縮

私は実際には、zlibを圧縮のためのバッファサイズを制限して使用しています。この制限に達すると、文字列が圧縮され、チャンネルに送信されます。これは機能しますが、情報が失われていない(チャンネルの入力制限が4096バイト)ために制限が低いため最適ではありません。

私の考えは、サイズの違う圧縮ブロックを使って圧縮バッファを増やし、チャネル入力制限に達する前にプロセスを停止するためにzlibを使用することです。 zlibは異なるサイズの圧縮ブロックで動作することができますか?別のアルゴリズムが必要ですか?

+0

本当にzlibについてのアイデアはありませんが、あなたの状況を処理できるLZMAを見てください。 http://7-zip.org/sdk.html – antipattern

答えて

0

制限された入力サイズのチャンネルを通して成長バッファを部分的に送るコンプレッサーの設計に成功しました。私はここで、同じ問題に取り組んでいる人に答えを出しました。 ThxからMark Adlerへ、 へ私を正しい道に導くためのMSalters。

class zStreamManager { 
    public: 
     zStreamManager(); 
     ~zStreamManager(); 
     void endStream(); 
     void addToStream(const void *inData, size_t inDataSize); 

    private: 
     // Size of base64 encoded is about 4*originalSize/3 + (3 to 6) 
     // so with maximum output size of 4096, 3050 max zipped out 
     // buffer will be fine 
     const size_t CHUNK_IN = 1024, CHUNK_OUT = 3050; 
     const std::string base64Chars = 
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
     "abcdefghijklmnopqrstuvwxyz" 
     "/"; 
     bool deallocated = true; 
     z_stream stream; 
     std::vector<uint8_t> outBuffer; 
     std::string base64Encode(std::vector<uint8_t> &str); 
}; 

zStreamManager::~zStreamManager() { 
    endStream(); 
} 

void zStreamManager::endStream() { 
    if(!deallocated) { 
     deallocated = true; 
     uint8_t tempBuffer[CHUNK_IN]; 
     int response = Z_OK; 
     unsigned int have; 

     while(response == Z_OK) { 
      if (stream.avail_out == 0) { 
       outBuffer.insert(outBuffer.end(), tempBuffer, tempBuffer + CHUNK_IN); 
       stream.next_out = tempBuffer; 
       stream.avail_out = CHUNK_IN; 
      } 
      response = deflate(&stream, Z_FINISH); 
     } 

     have = CHUNK_IN - stream.avail_out; 
     if(have) 
      outBuffer.insert(outBuffer.end(), tempBuffer, tempBuffer + have); 

     deflateEnd(&stream); 

     if(outBuffer.size()) 
      SEND << outBuffer << "$"; 
    } 
} 

void zStreamManager::addToStream(const void *inData, size_t inDataSize) { 
    if(deallocated) { 
     deallocated = false; 
     stream.zalloc = 0; 
     stream.zfree = 0; 
     stream.opaque = 0; 
     deflateInit(&stream, 9); 
    } 

    std::vector<uint8_t> tempBuffer(inDataSize); 
    unsigned int have; 

    stream.next_in = reinterpret_cast<uint8_t *>(const_cast<void*>(inData)); 
    stream.avail_in = inDataSize; 
    stream.next_out = &tempBuffer[0]; 
    stream.avail_out = inDataSize; 

    while (stream.avail_in != 0) { 
     deflate(&stream, Z_SYNC_FLUSH); 
     if (stream.avail_out == 0) { 
      outBuffer.insert(outBuffer.end(), tempBuffer.begin(), tempBuffer.begin() + inDataSize); 
      stream.next_out = &tempBuffer[0]; 
      stream.avail_out = inDataSize; 
     } 
    } 

    have = inDataSize - stream.avail_out; 
    if(have) 
     outBuffer.insert(outBuffer.end(), tempBuffer.begin(), tempBuffer.begin() + have); 

    while(outBuffer.size() >= CHUNK_OUT) { 
     std::vector<uint8_t> zipped; 

     zipped.insert(zipped.end(), outBuffer.begin(), outBuffer.begin() + CHUNK_OUT); 
     outBuffer.erase(outBuffer.begin(), outBuffer.begin() + CHUNK_OUT); 

     if(zipped.size()) 
      SEND << zipped << "|"; 
    } 
} 

std::string zStreamManager::base64Encode(std::vector<uint8_t> &str) { 
    /* ALTERED VERSION OF René Nyffenegger BASE64 CODE 
    Copyright (C) 2004-2008 René Nyffenegger 

    This source code is provided 'as-is', without any express or implied 
    warranty. In no event will the author be held liable for any damages 
    arising from the use of this software. 

    Permission is granted to anyone to use this software for any purpose, 
    including commercial applications, and to alter it and redistribute it 
    freely, subject to the following restrictions: 

    1. The origin of this source code must not be misrepresented; you must not 
     claim that you wrote the original source code. If you use this source code 
     in a product, an acknowledgment in the product documentation would be 
     appreciated but is not required. 

    2. Altered source versions must be plainly marked as such, and must not be 
     misrepresented as being the original source code. 

    3. This notice may not be removed or altered from any source distribution. 

    René Nyffenegger [email protected] 
    */ 
    unsigned char const* bytes_to_encode = &str[0]; 
    unsigned int in_len = str.size(); 
    std::string ret; 
    int i = 0, j = 0; 
    unsigned char char_array_3[3], char_array_4[4]; 

    while(in_len--) { 
    char_array_3[i++] = *(bytes_to_encode++); 
    if (i == 3) { 
     char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 
     char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 
     char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 
     char_array_4[3] = char_array_3[2] & 0x3f; 

     for(i = 0; (i <4) ; i++) 
     ret += base64Chars[char_array_4[i]]; 
     i = 0; 
    } 
    } 

    if(i) { 
    for(j = i; j < 3; j++) 
     char_array_3[j] = '\0'; 

    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 
    char_array_4[3] = char_array_3[2] & 0x3f; 

    for(j = 0; (j < i + 1); j++) 
     ret += base64Chars[char_array_4[j]]; 

    while((i++ < 3)) 
     ret += '='; 
    } 

    return ret; 
} 

ユースケース:RECEIVESEND、バッファを受信し、チャネルを介して送信するために使用される方法で

zStreamManager zm; 
string growingBuffer = ""; 
bool somethingToSend = true; 

while(somethingToSend) { 
    RECEIVE(&growingBuffer); 
    if(growingBuffer.size()) { 
    zm.addToStream(growingBuffer.c_str(), growingBuffer.size()); 
    growingBuffer.clear(); 
    } else { 
    somethingToSend = false; 
    } 
} 

zm.endStream(); 

。圧縮解除のために、各部分は '|'バッファ全体の終わりは '$'で区切られています。各パートは、base64でデコードされ、次に連結されなければなりません。最後に、他の圧縮データのようにzlibで圧縮解除することができます。

1

最も簡単な解決策は、帯域外パケットの記述をインバンド形式に変換することです。これを行う最も簡単な方法は、入力ブロックがすべての可能な256バイトを使用しない場合です。例えば。値00がブロック内に出現しない場合、それは圧縮の前にブロックを分離するために使用することができる。それ以外の場合は、エスケープコードが必要です。

どちらの方法でも、ブロックセパレータで連続ストリームを圧縮します。受信側では、ストリームを解凍し、セパレータを認識し、ブロックを再構築します。

1

4KBの圧縮データが生成されるたびに、連続したzlib圧縮を実行して、チャネル上のデータを送信するだけで済みます。もう一方の側では、デコンプレッサに圧縮データの4Kブロックが正しい順序で供給されることを保証する必要があります。

zlibのdeflateアルゴリズムは、圧縮データを放出する前に内部的に16Kから64Kまたはそれ以上のデータを累積した後、圧縮データのブロックを配信してから再び蓄積します。したがって、フラッシュデータを収縮させることを要求しない限り、レイテンシが発生します。レイテンシを減らしたい場合は、フラッシングによってブロックを小さくし、圧縮に多少の影響を与えることができます。

+0

私は圧縮ブロック(zlibの使用例では '' 'CHUNK''変数)と混同していますが、実際には固定サイズにすることができます。私が理解しているところは、 '' deflateEnd'''関数を呼び出すことを避け、 '' '' true''に '' '' flush'''を置く必要があるということです。私はいくつかのテストをする必要があります。あなたの答えはThx。 –

関連する問題