3

Qt を使用して NMDC クライアント (p2p、DC++ など) に取り組んでいます。プロトコル自体は非常に簡単です。

$command parameters|

圧縮を除く:

「ZPipe は、コマンド $ZOn| をクライアントに送信することによって機能します。$ZOn の後、コマンドを含む ZLib 圧縮ストリームが続きます。このストリームは、ZLib が定義する EOF で終了します。(圧縮ストリームには $ZOff はありません!)」

関連するコードは次のとおりです。

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_stream、およびの値を取得するにはどうすればよいremainder_of_dataでしょうか。ストリームに含まれている可能性があるため、次の「$」を探すことができません。zlib ドキュメントで EOF に似たものを探してみましたが、そのようなものはありません。実際、すべてのストリームは一見ランダムな文字で終了します。

私も qUncompress() をいじりましたが、それは完全なストリームを必要とします。

4

2 に答える 2

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から借りたほうがいいかもしれません。

于 2009-10-28T16:39:32.260 に答える
0

ファイルの終わりはzlibにとって特別なものではありません。私があなたのコードで見た問題は、「readAll()」を使用していることです。これには、ファイルの終わりなどの「エラー」を報告する手段が実際にはありません。

代わりに、ループで「read()」を使用してみてください。ストリームを読み取り、読み取り値が0バイトを返す場合は、ストリームの終わりに到達したことを確認できます(もう一方の端が接続を閉じています)。読んだバッファは、ループ内の以前のすべての「読み取り」のバッファと結合して、完全なバッファを提供します。

于 2009-10-28T15:29:48.660 に答える