Pergunta

Eu estou trabalhando em um cliente NMDC (p2p, DC ++ e amigos) com Qt. O protocolo em si é bastante simples:

$command parameters|

compressão :

"ZPipe funciona enviando um comando $ ZON |. Para o cliente Após $ ZON um fluxo comprimido ZLib contendo comandos seguirá Este fluxo vai acabar com um EOF que define ZLib (não existe $ Zoff no fluxo comprimido.. !) "

Aqui está o código relevante:

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);
}

Então, como faço para obter os valores para stream_is_complete, uncompressed_stream e remainder_of_data? Eu não posso olhar para a próxima '$' porque o fluxo pode contê-lo. Eu tentei olhar para algo parecido com um EOF na documentação zlib, mas não existe tal coisa, na verdade, todos os fins de fluxo com um caráter aparentemente aleatório.

Eu também brinquei com qUncompress (), mas que quer um fluxo completo, nada menos, nada mais.

Foi útil?

Solução

Você está usando zlib diretamente?

Totalmente testado ...

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
}

Esta forma incremental descomprime (inflar) de qbuffer para qout, e pára quando inflate diz "não mais".

Talvez seria melhor tomar emprestado de QuaZip .

Outras dicas

O fim do arquivo não é especial para zlib. O problema que vejo com o seu código é que você use "readAll ()", que na verdade não tem nenhum meio de relatórios "erros", como o fim do arquivo.

Você deve tentar usar "read ()" em vez disso, em um loop. Se você ler o fluxo e retorna 0 bytes ler, você pode ter certeza que você tenha atingido o fim do fluxo (a outra extremidade fechou a conexão). O buffer que você leu, juntando-as de toda a anterior "lê" no circuito, vai dar-lhe o tampão completo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top