2009-10-28 82 views
2

我正在使用Qt開發NMDC客戶端(p2p,DC++和朋友)。該協議本身是非常簡單的:查找zlib壓縮流的結尾

$command parameters| 

除了compression

「ZPipe通過發送一個命令$ ZON |給客戶端$ ZON經過了ZLib壓縮的含流命令將隨之而來。此流將與zlib的定義EOF結束(沒有$佐夫的壓縮數據流中!)」

下面是相關代碼:

QTcpSocket *conn; 
bool compressed; 
QByteArray zbuffer; 
QByteArray buffer; 

// ... 

void NMDCConnection::on_conn_readyRead() { 
    // this gets called whenever we get new data from the hub 

    if(compressed) {   // gets set when we receive $ZOn 
     zbuffer.append(conn->readAll()); 


     // Magic happens here 


     if(stream_is_complete) { 
      buffer.append(uncompressed_stream); 
      buffer.append(remainder_of_data); 
      compressed = false; 
     } 
    } else { 
     buffer.append(conn->readAll()); 
    }; 
    parse(buffer); 
} 

那麼,如何獲得stream_is_complete,uncompressed_streamremainder_of_data的值?我無法查找下一個'$',因爲該流可以包含它。我嘗試在zlib文檔中尋找類似EOF的東西,但是沒有這樣的東西,事實上,每個流都以一個看似隨機的字符結尾。

我也玩過qUncompress(),但是想要一個完整的流,沒有什麼比這更簡單了。

回答

1

您是直接使用zlib嗎?

完全未經測試...

z_stream zstrm; 
QByteArray zout; 
// when you see a $ZOn|, initialize the z_stream struct 
parse() { 
    ... 
    if (I see a $ZOn|) { 
     zstrm.next_in = Z_NULL; 
     zstrm.avail_in = 0; 
     zstrm.zalloc = Z_NULL; 
     zstrm.zfree = Z_NULL; 
     zstrm.opaque = 0; 
     inflateInit(&zstrm); 
     compressed = true; 
    } 
} 
void NMDCConnection::on_conn_readyRead() { 
    if (compressed) { 
     zbuffer.append(conn->readAll()); 
     int rc; 
     do { 
      zstrm.next_in = zbuffer.data(); 
      zstrm.avail_in = zbuffer.size(); 
      zout.resize(zstrm.total_out + BLOCK_SIZE); 
      zstrm.next_out = zout.data() + zstrm.total_out; 
      zstrm.avail_out = BLOCK_SIZE; 
      rc = inflate(&zstrm, Z_SYNC_FLUSH); 
      zbuffer.remove(0, zstrm.next_in - zbuffer.data()); 
     } while (rc == Z_OK && zstrm->avail_out == 0); 
     if (rc == Z_STREAM_END) { 
      zout.truncate(zstrm.total_out); 
      buffer.append(zout); 
      zout.clear(); 
      buffer.append(zbuffer); 
      zbuffer.clear(); 
      compress = false; 
      inflateEnd(&zstrm); 
     } 
     else if (rc != Z_OK) { 
      // ERROR! look at zstrm.msg 
     } 
    } 
    else // whatever 
} 

這逐漸解壓從qbuffer(膨脹),以qout,而當inflate說: 「沒有更多的」 停止。

也許最好從QuaZip借錢。

+0

嗯,一個明顯的改進就是不斷地將'zout'漸進地刷入'buffer' - 這樣你甚至可以在壓縮流全部到達之前開始分析。另一方面,在'$ ZOn |'內看到一個'$ ZOn |'將會是非常可怕的...... – ephemient 2009-10-28 16:59:33

0

文件的結尾對zlib並不特別。我在代碼中看到的問題是,您使用「readAll()」,實際上它沒有任何報告「錯誤」的方式,如文件結尾。

您應該嘗試在循環中使用「read()」。如果您讀取流並返回0字節讀取,您可以確定您已達到流結束(另一端已關閉連接)。你讀過的緩衝區,連接循環中所有前面的「讀取」,會給你完整的緩衝區。

+0

不,不,不。 QTcpSocket上的「文件結束」意味着我們斷開連接,斷開連接()信號將被觸發。 readyRead()具體意味着我們有新的可解析數據。我正在尋找的EOF是壓縮段的結尾,我們恢復正常的未壓縮協議。 – 2009-10-28 15:33:26

+0

啊,好吧,我現在明白了。 – 2009-10-28 17:14:53