Сжатие C ++ / zlib / gzip и декомпрессия C # GZipStream завершается неудачно

Я знаю, что есть множество вопросов о zlib / gzip и т.д., но ни один из них не совсем соответствует тому, что я пытаюсь сделать (или, по крайней мере, я не нашел его) В качестве краткого обзора, у меня есть сервер C #, который распаковывает входящие строки с помощью GZipStream. Моя задача — написать клиент C ++, который будет сжимать строку, совместимую с декомпрессией GZipStream.

Когда я использую приведенный ниже код, я получаю сообщение об ошибке: «Магическое число в заголовке GZip неверно. Убедитесь, что вы передаете поток GZip». Я понимаю, что такое магическое число и все такое, я просто не знаю, как правильно установить его магическим образом.

Наконец, я использую пакет C ++ zlib nuget, но также использовал исходные файлы непосредственно из zlib с той же неудачей.

Вот более глубокий взгляд:

Функция сервера для распаковки

public static string ReadMessage(NetworkStream stream)
{
byte[] buffer = new byte[512];
StringBuilder messageData = new StringBuilder();
GZipStream gzStream = new GZipStream(stream, CompressionMode.Decompress, true);
int bytes = 0;

while (true)
{
try
{
bytes = gzStream.Read(buffer, 0, buffer.Length);
}
catch (InvalidDataException ex)
{
Console.WriteLine($"Busted: {ex.Message}");
return "";
}

// Use Decoder class to convert from bytes to Default
// in case a character spans two buffers.
Decoder decoder = Encoding.Default.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
Console.WriteLine(messageData);
// Check for EOF or an empty message.
if (messageData.ToString().IndexOf("<EOF>", StringComparison.Ordinal) != -1)
break;
}
int eof = messageData.ToString().IndexOf("<EOF>", StringComparison.Ordinal);
string message = messageData.ToString().Substring(0, eof).Trim();

//Returns message without ending EOF
return message;
}

Подводя итог, он принимает NetworkStream, получает сжатую строку, распаковывает ее, добавляет ее в строку и выполняет цикл, пока не найдет <EOF> который удаляется, затем возвращает окончательную распакованную строку. Это почти совпадает с примером из MSDN.

Вот клиентский код C ++:

char* CompressString(char* message)
{
int messageSize = sizeof(message);

//Compress string
z_stream zs;
memset(&zs, 0, sizeof(zs));

zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.next_in = reinterpret_cast<Bytef*>(message);
zs.avail_in = messageSize;

int iResult = deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED, (MAX_WBITS + 16), 8, Z_DEFAULT_STRATEGY);
if (iResult != Z_OK) zerr(iResult);

int ret;
char* outbuffer = new char[messageSize];
std::string outstring;

// retrieve the compressed bytes blockwise
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = sizeof(outbuffer);

ret = deflate(&zs, Z_FINISH);

if (outstring.size() < zs.total_out) {
// append the block to the output string
outstring.append(outbuffer,
zs.total_out - outstring.size());
}
} while (ret == Z_OK);

deflateEnd(&zs);

if (ret != Z_STREAM_END) {          // an error occurred that was not EOF
std::ostringstream oss;
oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
throw std::runtime_error(oss.str());
}

return &outstring[0u];
}

Короче говоря, он принимает строку и проходит довольно стандартное сжатие zlib с настройками WBITS, чтобы обернуть его в заголовок / колонтитул gzip. Затем он возвращает символ * сжатого ввода. Это то, что отправляется на сервер выше для распаковки.

Спасибо за любую помощь, вы можете дать мне! Кроме того, дайте мне знать, если вам нужна дополнительная информация.

1

Решение

В вашем CompressString функция, которую вы возвращаете char* полученный из местного std::string, Строка будет уничтожена, когда функция вернется, что освободит память по указателю, который вы вернули.

Вероятно, что-то выделяется для этой области памяти и записывается поверх ваших сжатых данных, прежде чем они будут отправлены.

Необходимо убедиться, что память, содержащая сжатые данные, остается выделенной до тех пор, пока она не будет отправлена. Возможно, передав std::string& в функцию и хранить его там.

Несвязанная ошибка: вы делаете char* outbuffer = new char[messageSize]; но нет вызова delete[] для этого буфера. Это приведет к утечке памяти. Поскольку вы выкидываете исключения из этой функции, я бы рекомендовал использовать std::unique_ptr<char[]> вместо того, чтобы пытаться вручную разобраться с вашим собственным delete[] звонки. На самом деле я всегда рекомендую std::unique_ptr вместо явных призывов к delete если возможно.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]