LINUX.ORG.RU

Как потоком сжимать данные, отправлямые в сокет?

 , ,


0

1

Попробовал IO::Compress::Gzip->new($sock) - что-то не работает оно так совсем. Уж и autoflush ставил, и убирал - ничего не помогает :(

Вообще насколько я помню, основные алгоритмы сжатия основаны на словарях - по логике, чем больше нужно клиенту данных отправить в сжатом виде, тем обширнее словарь, но в таком случае помимо самих данных нужно с каждой новой порцией сжатого потока выдавать ещё и обновления словаря, если они вообще есть.

Искал в гугле IO::Compress::Gzip socket - ничего не нашёл.

Если сжимать данные теми «кусочками», которыми они дискретно формируются - получится невыгодно, поскольку кусочки просто мизерные, есть смысл сжимать всё это только как поток.

Ну и в целом - есть ли вообще какая-то общеизвестная методика, как сжимать ответы и отправлять их в сокет? У меня всё отлично работает в ту сторону: исходные данные клиента жмутся, всё ОК. Но вот в обратку/ответами что-то какой-то лютый треш происходит: приходит только небольшая порция неконсистентных данных.

★★★★★

Ответ на: комментарий от Olegymous

Прекрасно, но нет.

Мне нужно делать так: если исходно клиент шлёт сжатые данные - отдавать ему сжатые данные. Если шлёт plaintext - отдавать ему plaintext.

Обнаруживаю по GZIP_MAGIC в первых 2-х байтах потока от клиента.

Внимание, вопрос: могу ли я после этого как-то неожиданно впихнуть дескриптору соотв. IO layer. Подозреваю, что нет.

DRVTiny ★★★★★ ()
Ответ на: комментарий от Olegymous

В качестве примера написал сжималку файла /etc/fstab в файл out.z:

#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Compress::Raw::Zlib;
use constant GZIP_MAGIC => 0x1f8b;
use constant OS_MAGIC => 0x03;
open my $fhI, '<', '/etc/fstab';
open my $fhO, '>', 'out.z';
syswrite($fhO, pack("nccVcc",GZIP_MAGIC,Z_DEFLATED,0,time(),0,OS_MAGIC));
my $i=1;
my ($d, $status) = new Compress::Raw::Zlib::Deflate();
my ($sumL, $sumCRC)=(0, crc32(undef));
while (sysread($fhI,my $l,32)) {
  $d->deflate($l, my $o);
  $d->flush($o, Z_SYNC_FLUSH);
  my $lo=length($o);
  say 'L=',$lo;
  $sumL+=$lo;
  $sumCRC=crc32($o, $sumCRC);
  syswrite($fhO, $o, length($o));
}
syswrite($fhO, pack('LL', $sumCRC, $sumL));
close $fhO;
close $fhI;

Содержимое файла gzip не читает, говорит про unexpected end of file.

Как правильно формировать сокетный поток в сторону клиента, не опираясь на layer'ы?

DRVTiny ★★★★★ ()
Ответ на: комментарий от Olegymous

«If you attempt to open a file for reading and writing the open will fail.»

У меня сервер. Он открывает сокет, читает данные клиента и пишет в него же данные клиента.

DRVTiny ★★★★★ ()
Ответ на: комментарий от DRVTiny

Содержимое файла gzip не читает, говорит про unexpected end of file.

gzip это не просто заголовок и поток байт, там еще метаданные есть (имя файла и время)

disarmer ★★★ ()
Ответ на: комментарий от Olegymous

Zlib обеспечивает само сжатие, Gzip - способ упаковки контейнера (потока или файла), т.е. оформления его заголовком.

DRVTiny ★★★★★ ()

Вообще насколько я помню, основные алгоритмы сжатия основаны на словарях - по логике, чем больше нужно клиенту данных отправить в сжатом виде, тем обширнее словарь, но в таком случае помимо самих данных нужно с каждой новой порцией сжатого потока выдавать ещё и обновления словаря, если они вообще есть.

Ты похоже не понял как работает потокове сжатие. Компрессор (например IO::Compress::Gzip) имеет свое состояние, которое не сбрасывается, если этого не сделать явно. И сжимать маленькими порциями - ничем не лучше сжатия большого куска одним махом в плане работы со словарями

annulen ★★★★★ ()

Кстати, если рассматривается возможность заменя алгоритма сжатия, своетую обратить внимание на zstd, он позволяет получить более высокую пропускную способность

annulen ★★★★★ ()
Ответ на: комментарий от disarmer

Решилось использованием более внятного интерфейса-надстройки Compress::Zlib. Теперь и сжимает, и «разжимает» :)

DRVTiny ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.