《從零開始搭建遊戲伺服器》 網路資料壓縮——Zlib演算法

河樂不為發表於2017-06-08

前言:

關於壓縮演算法,其實有不少,例如:ZIPRARbzip2等,這裡我們舉例使用的Zlib相較於前者都要簡單一些,與ZIPRAR等歸檔演算法不同,它與bzip2更為接近。那麼,下面我們就來嘗試一下Zlip在C#和Java中的實現和資料互動:C#中加密Java中解密;又或者是Java中加密C#中解密,這也體現了Zlib的跨平臺特性。

C#方面:

通常是指客戶端,例如Unity中,可以使用此壓縮方法來壓縮網路通訊的位元組資料,伺服器接收到資料之後再進行解壓,這樣可以節約網路通訊的流量損耗。

1.下載:

其實很簡單,直接查詢第三方類庫DotNetZipLib-DevKit-v1.9,下載其中的Ionic.Zip.dll庫檔案,其目錄為DotNetZipLib-DevKit-v1.9\zip-v1.9\Release\Ionic.Zip.dll,然後引入到專案中,其實也可以單獨下載.net版本的Zlib庫檔案,這裡使用到Ionic.Zip庫是因為其中繼承了幾種壓縮演算法,為了方便後續使用,匯入到應用專案中,可以檢視其結構目錄:

Ionic.Zip
--Ionic
--Ionic.BZip2
--Ionic.Crc
--Ionic.Zip
--Ionic.Zlib

這裡我們使用到的就是Ionic.Zlib這種壓縮演算法,這裡我們以壓縮byte[]為例,具體的壓縮和解壓步驟:

//引入庫
using Ionic.Zlib;

2.壓縮:

//壓縮位元組陣列
byte[] newData = ZlibStream.CompressBuffer(oldData);

3.解壓:

//解壓
byte[] oldData = ZlibStream.UncompressBuffer(newData);

Java版的Zlib:

通常是指伺服器,在JDK中的java.util.zip中就包含了內建的Zlib實現,我們只需要做簡單的封裝即可實現壓縮和解壓的功能,這裡我們封裝一下壓縮和解壓byte[]位元組陣列的方法在工具類 ZlibUtil 中:

1.壓縮:

    /**
     * 壓縮
     * @param data 待壓縮資料
     * @return byte[] 壓縮後的資料
     */
    public static byte[] compress(byte[] data) {  
        byte[] output = new byte[0];  

        Deflater compresser = new Deflater();  

        compresser.reset();  
        compresser.setInput(data);  
        compresser.finish();  
        ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);  
        try {  
            byte[] buf = new byte[1024];  
            while (!compresser.finished()) {  
                int i = compresser.deflate(buf);  
                bos.write(buf, 0, i);  
            }  
            output = bos.toByteArray();  
        } catch (Exception e) {  
            output = data;  
            e.printStackTrace();  
        } finally {  
            try {  
                bos.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
        compresser.end();  
        return output;  
    }  

2.解壓:

    /** 
     * 解壓
     * @param data      待壓縮的資料 
     * @return byte[]   解壓縮後的資料 
     */  
    public static byte[] decompress(byte[] data) {  
        byte[] output = new byte[0];  

        Inflater decompresser = new Inflater();  
        decompresser.reset();  
        decompresser.setInput(data);  

        ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);  
        try {  
            byte[] buf = new byte[1024];  
            while (!decompresser.finished()) {  
                int i = decompresser.inflate(buf);  
                o.write(buf, 0, i);  
            }  
            output = o.toByteArray();  
        } catch (Exception e) {  
            output = data;  
            e.printStackTrace();  
        } finally {  
            try {  
                o.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  

        decompresser.end();  
        return output;  
    }

3.測試:

        System.err.println("位元組壓縮/解壓縮測試");  
        String inputStr = "linshuhe.tech;linshuhe.tech;linshuhe.tech;linshuhe.tech;";  
        System.err.println("輸入字串:\t" + inputStr);  
        byte[] input = inputStr.getBytes();  
        System.err.println("輸入位元組長度:\t" + input.length);
        byte[] data = ZlibUtil.compress(input);  
        System.err.println("壓縮後位元組長度:\t" + data.length);
        byte[] output = ZlibUtil.decompress(data);  
        System.err.println("解壓縮後位元組長度:\t" + output.length);  
        String outputStr = new String(output);  
        System.err.println("輸出字串:\t" + outputStr);

執行程式碼輸出的測試結果如下:

位元組壓縮/解壓縮測試
輸入字串:  linshuhe.tech;linshuhe.tech;linshuhe.tech;linshuhe.tech;
輸入位元組長度: 56
壓縮後位元組長度:    25
解壓縮後位元組長度:   56
輸出字串:  linshuhe.tech;linshuhe.tech;linshuhe.tech;linshuhe.tech;

題外話:

Java中除了Zlib這種簡單的壓縮演算法之外,還有其他幾種常用的較複雜的壓縮演算法:

名稱 實現方式 效能
JDK GZIP java.util.zip.GZIPInputStream/GZIPOutputStream便可實現 壓縮比高,速度慢,壓縮後的資料適合長期使用
JDK deflate java.util.zip.DeflaterOutputStream/InflaterInputStream可實現 可指定演算法的壓縮級別,0(不壓縮)、1(快速壓縮)到9(慢速壓縮)
LZ4壓縮演算法 https://github.com/lz4/lz4/https://github.com/Cyan4973/lz4.githttps://github.com/lz4/lz4.git 對比幾種壓縮演算法裡面壓縮速度最快的
Snappy Google開發的 速度和壓縮比都相對較優

速度對比結果:
Snappy要慢於LZ4(快速壓縮),並且壓縮後的檔案要更大。相反,LZ4(高壓縮比)要慢於級別1到4的deflate,而輸出檔案的大小即便和級別1的deflate相比也要大上不少。因此如果需要進行“實時壓縮”的話我肯定會在LZ4(快速)的JNI實現或者是級別1的deflate中進行選擇。當然如果你的公司不允許使用第三方庫的話你也只能使用deflate了。

更多關於Zlib的內容參考:Zlib官網


參考資料:

相關文章