不知道有多少人有遇到跟我一樣的問題,就是Web Service的資料回傳量太大了,如果都是走區域網路的話,除非量很大,不然還感覺不太出來,可是,如果是透過ADSL的頻寬的話,那就很驚人了,以30MB的資料量來說,透過2M/512K的網路上傳,加上網路品質的損耗以65%來看,也大概要花738秒左右來上傳. (30*1024)/((512*0.65)/8)=738.46. 這樣的時間,看起來很嚇人,何況在上傳滿載時,下載的頻寬可能剩40%不到,如果今天能壓縮這資料量,讓資料量剩25%左右,那上傳時間就只要185秒左右,這樣的差異就很大了,如果今天我們採用的是n-tier架構,Client是透過Web Service在要資料,那要怎麼去壓縮這傳輸過程中的資料? 這時就可以拿GZipStream出來用了.

  起初,GZipStream只是被我拿來當檔案壓縮用的,剛好這段時間遇到公司ERP系統效能調校,突然產生了一個想法,如果我能拿它來壓縮資料,那傳輸的資料量不就小很多,尤其是XML的文字檔,效果一定更明顯,就在這個念頭下,著手開始寫了測試的程式,在這裡,我做了兩種不同的做法,一個是純壓縮,不Serialize,另一種做法是壓縮與Serialize,而這兩種做法,是會產生些微的資料量差異.

在提到程式內容之前,先說明這做法所造成的資料量差異,詳見下表 :

正常資料量

壓縮後

壓縮+Serialize

18,368,067 Bytes

4,755,570 Bytes

4,445,278 Bytes

17,937.57 Kb

4,644.11 Kb

4,341.09 Kb

接下來,就是程式碼部份,分兩個部份說明:

1 .純壓縮 :

WebService Side :

using System.IO;
using System.IO.Compression;
[WebMethod]
public byte[] getZipData()
{
DataSet ds = LoadData().Copy();
MemoryStream unMS = new MemoryStream();
ds.WriteXml(unMS);
byte[] bytes = unMS.ToArray();
int lenbyte = bytes.Length;
MemoryStream compMs = new MemoryStream();
GZipStream compStream = new GZipStream(compMs, CompressionMode.Compress, true);
compStream.Write(bytes, 0, lenbyte);
compStream.Close();
unMS.Close();
compMs.Close();
byte[] zipData = compMs.ToArray();
return zipData;
}
private DataSet LoadData()
{//產生測試資料用
DataSet ds = new DataSet();
DataTable dt = new DataTable("Test");
dt.Columns.Add("ProID",typeof(int));
dt.Columns.Add("ProName", typeof(string));
dt.Columns.Add("CreateTime", typeof(DateTime));
dt.Columns["ProID"].AutoIncrement = true;
for (int i = 0; i < 100000; i++)
{
DataRow dr = dt.NewRow();
dr["ProName"] = Guid.NewGuid().ToString();
dr["CreateTime"] = DateTime.Now.ToString();
dt.Rows.Add(dr);
}
ds.Tables.Add(dt);
ds.AcceptChanges();
return ds;
}

Client Side :

using System.IO.Compression;
using System.IO;
private void btn_ZipGet_Click(object sender, EventArgs e)
{
try
{
WS.Service1 wss = new WSZipDemo.WS.Service1();//WebReference
byte[] da = wss.getZipData();
MemoryStream input = new MemoryStream();
input.Write(da, 0, da.Length);
input.Position = 0;
GZipStream gzip = new GZipStream(input, CompressionMode.Decompress, true);
MemoryStream output = new MemoryStream();
byte[] buff = new byte[4096];
int read = -1;
read = gzip.Read(buff, 0, buff.Length);
while (read > 0)
{
output.Write(buff, 0, read);
read = gzip.Read(buff, 0, buff.Length);
}
gzip.Close();
byte[] rebytes = output.ToArray();
output.Close();
input.Close();
MemoryStream ms = new MemoryStream(rebytes);
DataSet ds = new DataSet();
ds.ReadXml(ms);
dataGridView1.DataSource = ds.Tables[0];
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

2. 壓縮+Serialize

Web Service Side :

using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
[WebMethod]
public byte[] getZipData()
{
DataSet ds = LoadData().Copy();
ds.RemotingFormat = SerializationFormat.Binary;
BinaryFormatter ser = new BinaryFormatter();
MemoryStream unMS = new MemoryStream();
ser.Serialize(unMS, ds);
byte[] bytes = unMS.ToArray();
int lenbyte = bytes.Length;
MemoryStream compMs = new MemoryStream();
GZipStream compStream = new GZipStream(compMs, CompressionMode.Compress, true);
compStream.Write(bytes, 0, lenbyte);
compStream.Close();
unMS.Close();
compMs.Close();
byte[] zipData = compMs.ToArray();
return zipData;
}
private DataSet LoadData()
{//產生測試資料用
DataSet ds = new DataSet();
DataTable dt = new DataTable("Test");
dt.Columns.Add("ProID",typeof(int));
dt.Columns.Add("ProName", typeof(string));
dt.Columns.Add("CreateTime", typeof(DateTime));
dt.Columns["ProID"].AutoIncrement = true;
for (int i = 0; i < 100000; i++)
{
DataRow dr = dt.NewRow();
dr["ProName"] = Guid.NewGuid().ToString();
dr["CreateTime"] = DateTime.Now.ToString();
dt.Rows.Add(dr);
}
ds.Tables.Add(dt);
ds.AcceptChanges();
return ds;
}

Client Side :

using System.IO.Compression;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
private void btn_ZipGet_Click(object sender, EventArgs e)
{
try
{
WS.Service1 wss = new WSZipDemo.WS.Service1();//WebReference
byte[] da = wss.getZipData();
MemoryStream input = new MemoryStream();
input.Write(da, 0, da.Length);
input.Position = 0;
GZipStream gzip = new GZipStream(input, CompressionMode.Decompress, true);
MemoryStream output = new MemoryStream();
byte[] buff = new byte[4096];
int read = -1;
read = gzip.Read(buff, 0, buff.Length);
while (read > 0)
{
output.Write(buff, 0, read);
read = gzip.Read(buff, 0, buff.Length);
}
gzip.Close();
byte[] rebytes = output.ToArray();
output.Close();
input.Close();
MemoryStream ms = new MemoryStream(rebytes);
BinaryFormatter bf = new BinaryFormatter();
object obj = bf.Deserialize(ms);
DataSet ds = (DataSet)obj;
dataGridView1.DataSource = ds.Tables[0];
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

  這兩種做法只是在部份的程式碼不一樣,但其它大多相同,如果是方法一,在WebService壓縮後Return,Client收到資料後,解壓縮即可,方法二則多了Serialize這部份,所以在WebService這邊,先Serialize,再壓縮,Client端收到後,先解壓縮再Deserialize. 不過,這個壓縮後的量,是很讓人滿意,如果在頻寬有限,又需要傳輸大量資料時,這個方法可以考慮看看. 因為這個是.Net 2.0以後才有的東西,公司現在的ERP還在.Net 1.0,所以.........殘念~

2008/04/29 補充 :

  最近有網友看到這篇文章,有些問題問我朋友,而朋友再來轉問我這個問題(真巧,網友問我朋友,我朋友再來問我),而提出的問題是,壓縮跟解壓是否很耗用CPU的效能? 答案是,不可能不用到CPU的效能,但它也不致於到"很耗用"的地步. 而這耗用率只能視設備狀況來判斷,以我的環境來說,Client端的電腦是P4 3GHT, 上面的這個例子跑的時候有個瞬間最高47%,不到一秒的時間,如果是未壓縮版的,瞬間最高為37%左右,所以大概多個10%吧.

  或許有人還是有疑慮怎麼可以增加CPU的Loading呢,這樣就不好了,這時我們就要換個角度來思考這個問題了,"效能成本"所在為何,我們的Bottleneck在那.CPU在科技的進步下,雙核四核的都推出了,CPU的效能是快速的在倍增中,而我們的網路呢? 絕大多數區域還在100MB,部份Server與Server是1G在連,而ADSL呢? 10M/1M或者是只能2M/512K,因為申請不到更快的頻寬,如果要更快,每月的費用就更高, 注意囉,上傳是1MB或512K哦,而且是多人共用的,所以就目前國內的網路環境來看,ADSL要到100M/100M,似乎還要很長的一段時間,而這段時間的CPU,也不知道已經成長到幾核心了,兩者之間怎麼取捨,就看大家的看法囉.

2008/5/30 補充

  因為一些朋友對這個方式感到有興趣,也在網路上找了一些文章,可是卻又發現了一些疑問,到底這個壓縮技術能用在什麼樣的情況下. 其中一位朋友傳給了我一個網址.Net DataTable 大量資料壓縮加密實測,也是說明用壓縮的方式來減少流量,一些測試結果也很詳盡,有興趣的人建議參考,只是朋友在他的文章開頭的地方看到 [開發 Web 或分散式系統],這是否代表Web網站也可以用? 這個答案當然是沒用的,試想,我們在Web Server壓縮,Client端用IE或Firefox怎麼解壓縮,網頁是無法用Gzipstream的方式來解壓縮來減少Web Server到Client的資料量,能壓一定要能解才有用,所以就不用再去列出那些可以及那些不行了,畢竟這還關係的架構上的問題,所以應用的關鍵就是"能壓要能解才能用".

  另一個問題就是選擇性的使用,壓縮的動作勢必用到系統的效能,如果全面性100%的採用壓縮,當使用者多,或操作頻率高時,資料量大,系統效能也會變的更加吃重,所以必需挑選幾個關鍵的傳輸來壓縮即可,不用連1K不到的資料量也在壓縮,除非Server很猛的,那就另當別論. 依我的情況,我會挑選幾個使用者的查詢作業來壓,依目前手頭上的分析資料來看,有個查詢作業使用頻率較高,資料量也是驚人,最高的資料量就一次高達33MB,平均起來跟其它作業比較,這作業的資料量佔了不小的比率,光這作業一天平均傳輸量650MB,壓縮後只剩162.5MB在傳,所以只壓縮這個作業的查詢動作,就可明顯的改善ADSL的頻寬瓶頸. 所以要視情況去選擇要壓縮的作業.

參考資料 :

MSDN GZipStream 類別

MSDN BinaryFormatter 建構函式 ()

藉由GZipStream的壓縮,來減少Web Service的傳輸量相关推荐

  1. 由GZipStream的压缩,減少Web Service的传输量

    不知道有多少人有遇到跟我一樣的問題,就是Web Service的資料回傳量太大了,如果都是走區域網路的話,除非量很大,不然還感覺不太出來,可是,如果是透過ADSL的頻寬的話,那就很驚人了,以30MB的 ...

  2. java geoprocessor_ArcGIS GeoEvent Processor for Server 安裝與配置 (僅適用於壓縮安裝包)...

    安裝步驟: 1.  導航至您的GeoEvent Processor產品壓縮包(例如:geoevent-10.2.0.1139.zip). 該壓縮包可能是您從 Bata 社區網站獲得,或者由開發團隊提供 ...

  3. linux探索之旅pdf,【Linux探索之旅】第四部分第一課:壓縮文件,解壓無壓力

    內容簡介 1.第四部分第一課:壓縮文件,解壓無壓力 2.第四部分第二課:SSH連接,安全快捷 壓縮文件,解壓無壓力 最近小編因為換工作,從南法搬到巴黎.折騰了很久. 網絡一直用的是公共的無線網,信號不 ...

  4. android 音频压缩 silk,微信音頻silk導出多個mp3,合並成一個mp3,壓縮大小

    特此綜合好多導出教程整理出大致完整操作流程. 目的:微信音頻導出然后按順序拼接成一個mp3 3種思路: 思路1:多個silk->多個mp3->1個mp3或其他音頻格式 * 電腦端微信,收藏 ...

  5. yui compressor php,在 PHP 使用 YUI Compressor 壓縮 JavaScript 跟 CSS

    我在寫程式的時候,習慣搭配程式註解一併撰寫.寫JavaScript就搭配JSDoc,寫CSS就搭配CSSDoc,寫著寫著程式碼就會非常非常地龐大,造成使用者每次都要下載過大的檔案內容而效率緩慢. YU ...

  6. 使用 RGBA4444 與 Dithering 減少記憶體用量

    在 2D 遊戲中,圖片一向在消耗的記憶體中占用最大的比例.尤其在記憶體資源寶貴的行動裝置上,為了減少記憶體使用量,縮減圖片的大小常常是最有效的方法. 大部份的遊戲會使用材質壓縮 (texture co ...

  7. 如何兼容並蓄Android Studio 與 Eclipse 的優點, 減少顧此失彼的缺憾

    在習慣用Eclipse開發Android, 又想在過渡到Android Studio時減少衝擊. 但卻想用Android Studio來開啟Eclipse專案的話(直接開啟是不被允許的), 又不想把E ...

  8. IT經理出招 電腦耗電減少

    在過去數十年中﹐耗電問題對信息技術(IT)經理來說已算不上什麼 大問題.隨著上世紀80年代個人電腦的誕生﹐曾經的大型電腦耗電問題得以解決﹐科研經費開始更多投向提高計算能力的研究. 現如今﹐IT經理們卻 ...

  9. oracle 减少回表,減少oracle sql回表次數 提高SQL查詢性能 | 學步園

    要寫出高效的SQL,那麼必須必須得清楚SQL執行路徑,介紹如何提高SQL性能的文章很多,這裡不再贅述,本人來談談如何從 減少SQL回表次數 來提高查詢性能,因為回表將導致掃描更多的數據塊. 我們大家都 ...

最新文章

  1. 调用ajax后页面为什么会刷新,为什么页面在JQuery ajax调用之后重新加载?
  2. MS CRM 2011 用Jscript打开新窗口的几种方法
  3. 使用循环计算斐波那契数列
  4. sudo spctl --master-disable_量大从优批发--阳离子聚丙烯酰胺--用于生活污水、
  5. 用户管理实例 之 添加、查询
  6. 云现场 | 为什么说边缘计算是5G时代的必备品?
  7. 02 button的练习
  8. 【PAT乙】1038 统计同成绩学生 (20分) 裸桶排序
  9. VS2010:外部依赖目录错误,怎么办
  10. ROS安装教程|从零开始
  11. Python爬虫之七:爬虫实战-爬取豆瓣电影 top 250
  12. 关于平面设计知识,设计师需要懂得印刷常识——黎乙丙
  13. android 休眠锁
  14. C语言基础之小写字母转大写
  15. Linux在安装文件时,yum基本配置出现错误
  16. 删除链接到WLW清单文件
  17. 实战:从零开始制作一个跑步微信小程序
  18. Redhat7升级内核(含安装yum)
  19. AXI总线学习(AXI34)
  20. 【loj2639】[Tjoi2017]不勤劳的图书管理员

热门文章

  1. vulnhub靶场——VULNERABLE DOCKER: 1 Easy
  2. 微信小程序全局存储信息
  3. shell脚本之脚本案例
  4. OSChina 周四乱弹 —— 把青春献给身后那座辉煌的都市
  5. 2020-04-22
  6. python画樱桃小丸子_学python画图最快的方式——turtle小海龟画图
  7. 数据质量管理_第四篇 对数变换
  8. outlook express: socket error 10053 0x800ccc0f
  9. vue下载excel模板
  10. 手机后缀名html文件可以删除吗,没有后缀的文件怎么删除 文件没有后缀,无法打开,更无法删除...