HTTP를 통해 일부 스트리밍 데이터를 제공하려고합니다. 또한 대역폭을 절약하기 위해 데이터를 압축하고 싶습니다. 필자는 개별적으로 각 스트리밍 응답을 개별적으로 압축 할 수 있지만 필자의 경우 모든 단일 클라이언트 (팬 아웃)에 대해 데이터 스트림이 거의 동일하므로 각 연결에 대해 동일한 데이터를 압축하는 데 CPU 시간이 낭비되는 것처럼 보입니다. 내 계획은 스트리밍 데이터의 각 청크를 선점 적으로 압축하는 것이므로 언제든지 연결하는 클라이언트는 다음 청크 읽기를 시작할 수 있습니다 (압축 효율은 낮아 지지만 개별 데이터 청크가 충분히 크면이 괜찮을거야).스트리밍 HTTP 클라이언트간에 DEFLATE 압축 데이터 청크를 교환하십시오.
호환 HTTP 클라이언트는 분명히 Content-Encoding: gzip
응답 인 but the answers to this question indicate web browsers do not의 여러 gzip 파일을 허용 할 수 있습니다. 그러나 DEFLATE/zlib을 이해하면 Z_FULL_FLUSH
0x0000FFFF
바이트를 보내 개별적으로 압축 할 수없는 청크와 동일한 효과를 제공하는 스트림을 재설정 할 수 있습니다.
node.js에 서버 보낸 이벤트 스트림으로 메시지를 스트리밍하는 간단한 POC를 설정했지만 웹 브라우저에서 데이터를 읽을 수 없습니다. 연결은 열리지 만 데이터는 플러시되지 않습니다. 단순화를 위해 Z_NO_COMPRESSION
을 사용하고 있습니다.
var http, zlib, gzip, numClients;
http = require('http');
zlib = require('zlib');
gzip = zlib.createDeflateRaw({
flush: zlib.Z_SYNC_FLUSH,
level: zlib.Z_NO_COMPRESSION
});
numClients = 0;
setInterval(function(){
if (numClients > 0) {
gzip.write("data: hi\n\n");
}
}, 1000);
http.createServer(function(req, res){
res.socket.setTimeout(Infinity);
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Content-Encoding': 'deflate',
'Transfer-Encoding': 'identity',
'Access-Control-Allow-Origin': '*'
});
res.write('\x78\x01'); // write zlib magic number
gzip.pipe(res);
numClients++;
res.on('close', function(){
numClients--;
gzip.unpipe(res);
});
res.on('error', function(){
numClients--;
gzip.unpipe(res);
});
}).listen(8080);
numClients++;
gzip.pipe(process.stdout);
그리고 간단한 클라이언트 :
0000000: 7801 000a 00f5 ff64 6174 613a 2068 690a x......data: hi.
0000010: 0a00 0000 ffff 000a 00f5 ff64 6174 613a ...........data:
0000020: 2068 690a 0a00 0000 ffff 000a 00f5 ff64 hi............d
0000030: 6174 613a 2068 690a 0a00 0000 ffff 000a ata: hi.........
0000040: 00f5 ff64 6174 613a 2068 690a 0a00 0000 ...data: hi.....
0000050: ffff 000a 00f5 ff64 6174 613a 2068 690a .......data: hi.
0000060: 0a00 0000 ffff 000a 00f5 ff64 6174 613a ...........data:
난에 DEFLATE 압축 해제에 대한 추가 프레임을 추가해야합니까 :
<!DOCTYPE html5>
<html lang=en>
<meta charset=utf-8>
<title>hi</title>
<script>
var es = new EventSource("http://localhost:8080/");
es.addEventListener('data', console.log);
es.addEventListener('open', console.log);
es.addEventListener('error', console.log);
</script>
바이트 수 (curl -N localhost:8080
가 xxd
을 통해 파이프), 다음과 같이 플러시 포인트를 감지 했습니까?
EDIT : http 스트림을 유효한 DEFLATE 스트림으로 만들기 위해 zlib magic number을 추가했지만 웹 브라우저는 여전히 블록을 플러시하지 않습니다. 그러나 zlib.createInflate()
을 통해 gzip
스트림을 다시 파이핑하면 매직 번호가 추가되면 올바르게 작동합니다. 또한 curl -N localhost:8080
은 원시 바이트를 표시하기 때문에 http 스트림이 버퍼링되지 않는다는 것도 알고 있습니다.
"마지막 블록"비트와 무결성 검사는 어떻게'Z_FULL_FLUSH'와 내 제한없는 스트림에서 재생됩니까? 모든 데이터 덩어리마다 마지막 블록 + 검사가 필요합니까? 압축 해제 기가 다른 블록의 무결성 검사를 넘어 읽을 것입니까? 내가 올바르게 당신을 이해한다면, 내 bytestream은 (마술) (저장 블록) * (01 00 00 ff ff) (Adler-32)) *'처럼 보일 것입니다. – blendmaster
마지막 블록과 체크는 끝 부분에 있습니다. 따라서 당신의 표기법에서, (마법) (풀 플러시 블록) * (01 00 00 ff ff) (애들러 -32)'. 데이터가있는 마지막 블록이 바이트 경계에서 끝나는 지 확인하려면 전체 플러시가 필요합니다. –
준비된 각 블록에 대해 Adler-32 검사를 미리 계산할 수 있으며 'adler32_combine()'을 사용하여 전체 스트림을 빌드 할 때 결합 할 수 있습니다. –