wmproxy
wmproxy
是由Rust
編寫,已實現(xiàn)http/https
代理,socks5
代理, 反向代理,靜態(tài)文件服務(wù)器,內(nèi)網(wǎng)穿透,配置熱更新等, 后續(xù)將實現(xiàn)websocket
代理等,同時會將實現(xiàn)過程分享出來, 感興趣的可以一起造個輪子法
項目 ++wmproxy++
gite: https://gitee.com/tickbh/wmproxy
github: https://github.com/tickbh/wmproxy
HTTP中壓縮的意義
HTTP中壓縮的意義在于降低了網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)量,從而提高客戶端瀏覽器的訪問速度。當(dāng)然,同時也會增加一點服務(wù)器的負(fù)擔(dān)。
HTTP/1.1協(xié)議中壓縮主要包括gzip壓縮和deflate壓縮兩種方法。其中g(shù)zip壓縮使用的是LZ77和哈夫曼編碼,而deflate壓縮使用的是LZ77和哈夫曼編碼以及霍夫曼編碼。
此外在2015年由Google公司開發(fā)的Brotli算法是也基本全面普及開來,Brotli算法的核心原理包括兩個部分:預(yù)定義的字典和無損壓縮算法。預(yù)定義的字典是Brotli算法中的一項關(guān)鍵技術(shù),它包含了一些常見的字符序列,例如Web標(biāo)記、HTML、CSS和JavaScript代碼等。Brotli算法的無損壓縮算法采用了一種基于模式匹配的壓縮方法。它通過預(yù)測數(shù)據(jù)中出現(xiàn)的重復(fù)模式,對數(shù)據(jù)進行壓縮。
在HTTP的壓縮協(xié)議中,這三種壓縮算法基本上可以全部被支持。
gzip,deflate,brotli的優(yōu)劣勢
gzip、deflate和brotli這三種壓縮算法都有各自的優(yōu)勢和劣勢,具體如下:
- gzip
- 優(yōu)勢:是Web上最常見的壓縮算法之一,具有較高的壓縮效率和廣泛的支持程度,可以被幾乎所有的瀏覽器和服務(wù)器支持。
- 劣勢:算法的壓縮比相對較低,可能會增加文件的大小。
- deflate
- 優(yōu)勢:具有較高的壓縮效率和廣泛的支持程度,同時算法的實現(xiàn)在不同的瀏覽器和服務(wù)器之間非常一致。
- 劣勢:由于某些實現(xiàn)上的缺陷,可能會導(dǎo)致一些瀏覽器和服務(wù)器無法正常解壓縮。
- brotli
- 優(yōu)勢:具有更高的壓縮效率和更快的壓縮速度,可以進一步減少傳輸數(shù)據(jù)的大小,從而提高頁面加載速度,并且被較新版本的瀏覽器和服務(wù)器支持。
- 劣勢:由于算法目前僅被較新版本的瀏覽器和服務(wù)器支持,因此需要根據(jù)實際情況進行選擇。
以下是壓縮解壓的數(shù)率圖:
數(shù)據(jù)來源src
可以看出brotli的壓縮比大概在9左右,gzip大概在7左右,deflate也大概在7左右,壓縮比brotli最高,適應(yīng)網(wǎng)絡(luò)傳輸慢的情況,壓縮速度gzip和deflate相對較快,解壓縮deflate較快,brotli和gzip差不多。
rust中三種壓縮方式庫的選擇
通常尋找rust中的第三方庫的時候,可以通過https://crates.io/
進行選擇,這里公開的第三方庫都會在這里顯示,包括使用次數(shù),流行熱度,最近下載量,最近更新時間等,可以從多維度的知道該庫的好與壞再進行相應(yīng)的選擇。
-
flate2
該庫支持三種壓縮格式的算法,deflate
, zlib
, gzip
,我們選擇用它來做deflate
, gzip
的支持。
-
brotli
該庫如庫名一般,只支持brotli
算法,相對熱度較高,算是支持brolti里最好的一個,我們進行選擇。
三種方式的壓縮實現(xiàn)
三種方式均可實現(xiàn)流式的壓縮,即邊寫入數(shù)據(jù),邊讀出壓縮數(shù)據(jù),不用完全的寫入所有數(shù)據(jù),完整的實現(xiàn)方法在 RecvStream里,將壓縮的數(shù)據(jù)緩存到
self.cache_body_data
中
定義壓縮方法值
pub const COMPRESS_METHOD_NONE: i8 = 0;
pub const COMPRESS_METHOD_GZIP: i8 = 1;
pub const COMPRESS_METHOD_DEFLATE: i8 = 2;
pub const COMPRESS_METHOD_BROTLI: i8 = 3;
- gzip
此處利用的是類
use flate2::write::GzEncoder
,定義為GzEncoder<BinaryMut>
,其中BinaryMut為壓縮后的數(shù)據(jù),需要具備std::io::Write
方法。
Consts::COMPRESS_METHOD_GZIP => {
// 數(shù)據(jù)結(jié)束,需要主動調(diào)用結(jié)束以導(dǎo)出全部結(jié)果
if data.len() == 0 {
self.compress.open_write_gz();
let gz = self.compress.write_gz.take().unwrap();
let value = gz.finish().unwrap();
if value.remaining() > 0 {
Self::inner_encode_data(&mut self.cache_body_data, &value, self.is_chunked)?;
}
if self.is_chunked {
Helper::encode_chunk_data(&mut self.cache_body_data, data)
} else {
Ok(0)
}
} else {
self.compress.open_write_gz();
let gz = self.compress.write_gz.as_mut().unwrap();
gz.write_all(data).unwrap();
// 每次寫入,在嘗試讀取出數(shù)據(jù)
if gz.get_mut().remaining() > 0 {
let s =
Self::inner_encode_data(&mut self.cache_body_data, &gz.get_mut().chunk(), self.is_chunked);
gz.get_mut().clear();
s
} else {
Ok(0)
}
}
}
- deflate
此處利用的是類
use flate2::write::DeflateEncoder
,定義為DeflateEncoder<BinaryMut>
,其中BinaryMut為壓縮后的數(shù)據(jù),需要具備std::io::Write
方法。
Consts::COMPRESS_METHOD_DEFLATE => {
// 數(shù)據(jù)結(jié)束,需要主動調(diào)用結(jié)束以導(dǎo)出全部結(jié)果
if data.len() == 0 {
self.compress.open_write_de();
let de = self.compress.write_de.take().unwrap();
let value = de.finish().unwrap();
if value.remaining() > 0 {
Self::inner_encode_data(&mut self.cache_body_data, &value, self.is_chunked)?;
}
if self.is_chunked {
Helper::encode_chunk_data(&mut self.cache_body_data, data)
} else {
Ok(0)
}
} else {
self.compress.open_write_de();
let de = self.compress.write_de.as_mut().unwrap();
de.write_all(data).unwrap();
// 每次寫入,在嘗試讀取出數(shù)據(jù)
if de.get_mut().remaining() > 0 {
let s =
Self::inner_encode_data(&mut self.cache_body_data, &de.get_mut().chunk(), self.is_chunked);
de.get_mut().clear();
s
} else {
Ok(0)
}
}
}
- brotli
此處利用的是類
use brotli::CompressorWriter;
,定義為CompressorWriter<BinaryMut>
,其中BinaryMut為壓縮后的數(shù)據(jù),需要具備std::io::Write
方法。
Consts::COMPRESS_METHOD_BROTLI => {
// 數(shù)據(jù)結(jié)束,需要主動調(diào)用結(jié)束以導(dǎo)出全部結(jié)果
if data.len() == 0 {
self.compress.open_write_br();
let mut de = self.compress.write_br.take().unwrap();
de.flush()?;
let value = de.into_inner();
if value.remaining() > 0 {
Self::inner_encode_data(&mut self.cache_body_data, &value, self.is_chunked)?;
}
if self.is_chunked {
Helper::encode_chunk_data(&mut self.cache_body_data, data)
} else {
Ok(0)
}
} else {
self.compress.open_write_br();
let de = self.compress.write_br.as_mut().unwrap();
de.write_all(data).unwrap();
// 每次寫入,在嘗試讀取出數(shù)據(jù)
if de.get_mut().remaining() > 0 {
let s =
Self::inner_encode_data(&mut self.cache_body_data, &de.get_mut().chunk(), self.is_chunked);
de.get_mut().clear();
s
} else {
Ok(0)
}
}
}
三種方式的解壓實現(xiàn)
和壓縮不同的是,解壓的時候必須將完整的數(shù)據(jù)進行解壓,所以需要收到全部的數(shù)據(jù)的時候才嘗試進行解壓,可能我的理解有誤,歡迎指出,當(dāng)下的實現(xiàn)方式可能會占用大量的內(nèi)存,非我所愿。主要源碼在 SendStream中實現(xiàn)。
三種方式均類似,以下
// 收到數(shù)據(jù)進行緩存,只有到結(jié)束時才進行解壓縮
match self.compress_method {
Consts::COMPRESS_METHOD_GZIP => {
self.cache_body_data.put_slice(data);
if self.is_end {
self.compress.open_reader_gz(self.cache_body_data.clone());
let gz = self.compress.reader_gz.as_mut().unwrap();
let s = Self::read_all_data(&mut self.cache_buf, &mut self.real_read_buf, gz);
self.cache_body_data.clear();
s
} else {
Ok(0)
}
}
Consts::COMPRESS_METHOD_DEFLATE => {
self.cache_body_data.put_slice(data);
if self.is_end {
self.compress.open_reader_de(self.cache_body_data.clone());
let de = self.compress.reader_de.as_mut().unwrap();
let s = Self::read_all_data(&mut self.cache_buf, &mut self.real_read_buf, de);
self.cache_body_data.clear();
s
} else {
Ok(0)
}
}
Consts::COMPRESS_METHOD_BROTLI => {
self.cache_body_data.put_slice(data);
if self.is_end {
self.compress.open_reader_br(self.cache_body_data.clone());
let br = self.compress.reader_br.as_mut().unwrap();
let s = Self::read_all_data(&mut self.cache_buf, &mut self.real_read_buf, br);
self.cache_body_data.clear();
s
} else {
Ok(0)
}
}
_ => {
self.real_read_buf.put_slice(data);
Ok(data.len())
},
}
如果數(shù)據(jù)包非常的巨大的時候,可能需要將內(nèi)存內(nèi)容寫入緩存文件來緩解內(nèi)存的壓力。文章來源:http://www.zghlxwxcb.cn/news/detail-787094.html
結(jié)語
壓縮為了可以更好的存儲,也可以更好的傳輸,是我們?nèi)粘I钪斜夭豢缮俚拇嬖?,雖然現(xiàn)在比以前帶寬更高,存儲比之前的更便宜,但是現(xiàn)在的數(shù)據(jù)更多,傳輸延時要求更少,所以高壓縮的能力依然非常受歡迎。文章來源地址http://www.zghlxwxcb.cn/news/detail-787094.html
到了這里,關(guān)于13. 從零用Rust編寫正反向代理, HTTP中的壓縮gzip,deflate,brotli算法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!