簡介
我用的是1.6版,附百度雲地址鏈接:http://pan.baidu.com/s/1dDzW4XN 密碼:xz6a
Unity用來和服務器通信可以用原生的WWW,但是WWW所提供的功能並不多,不能滿足很多需求。因此我們可以自己封裝Http協議來滿足更多的需要。在Unity游戲里使用Http協議的情況很常見,因為它操作簡單,便於實現,經常用在登陸等場景下,還例如下載上傳一些資源。如果想要實現進一步的控制,就要使用Socket並定義自己的協議了。
使用這個插件還有一個重點就在跨平台,因為用C#自己的HttpWebRequest也能實現。
下面簡要介紹一下HTTP和Socket:
Http連接:http連接就是所謂的短連接,即客戶端向服務器端發送一次請求,服務器端響應后連接即會斷掉;慢,不太適合游戲中實時數據的傳輸。數據量。
由於HTTP在每次請求結束后都會主動釋放連接,因此HTTP連接是一種“短連接”,要保持客戶端程序的在線狀態,需要不斷地向服務器發起連接請求。通常的做法是即時不需要獲得任何數據,客戶端也保持每隔一段固定的時間向服務器發送一次“保持連接”的請求,服務器在收到該請求后對客戶端進行回復,表明知道客戶端“在線”。若服務器長時間無法收到客戶端的請求,則認為客戶端“下線”,若客戶端長時間無法收到服務器的回復,則認為網絡已經斷開。
Socket連接:socket連接就是所謂的長連接,理論上客戶端和服務器端一旦建立起連接將不會主動斷掉;但是由於各種環境因素可能會是連接斷開,比如說:服務器端或客戶端主機down了,網絡故障,或者兩者之間長時間沒有數據傳輸,網絡防火牆可能會斷開該連接以釋放網絡資源。所以當一個socket連接中沒有數據的傳輸,那么為了維持連接需要發送心跳消息~~具體心跳消息格式是開發者自己定義的。
關於Socket連接與HTTP連接的區別,請參考
http://www.cnblogs.com/devinzhang/archive/2012/01/13/2321826.html
http://www.xuanyusong.com/archives/1948
BestHttp是基於RFC 2616的Http/1.1實現,支持幾乎所有Unity支持的移動和主機平台,具體請見官方文檔。
以下介紹主要來自於官方文檔,會有一些補充信息。
BestHttp的目標是成為一款充分發揮Http/1.1潛力的,易用並且強大的Unity插件。
安裝:
需要將BestHttp目錄下的Plugins目錄移動到Assets目錄下,實際上腳本BestHTTPInstaller.cs會在導入完成后自動的完成這個過程,這里用到了[InitializeOnLoad]這個特性,我們稍后再說。
需要注意的一點是Unity低於3.5版本的話,需要刪除Plugins目錄下的WP8目錄。
接下來開始一些基礎的介紹:
首先添加Using BestHttp; 的聲明
Get Requests
最簡單的向服務器發出請求的辦法是創建一個HttpRequest對象,提供url和一個回調函數給構造函數。在創建了一個新的HttpRequest對象之后,我們只需要調用Send()函數就可以發送請求了。
下面看一個例子:
1 HTTPRequest request = new HTTPRequest(new Uri(“https://google.com”), onRequestFinished); 2 request.Send(); 3 void OnRequestFinished(HTTPRequest request, HTTPResponse response) 4 { 5 Debug.Log(“Request Finished! Text received: ” + response.DataAsText); 6 }
回調函數會收到兩個參數,一個是原始的HTTPRequest 對象,另一個是承載服務器響應的HTTPResponse 對象。如果出錯的話,HTTPResponse 對象會是空,並且帶有一個Exception屬性來顯示可能的錯誤。請求是分別在不同的線程中處理的,而調用回調函數是在Unity的主線程中,所以我們不必去做任何的線程同步。
在這個例子里我們都不需要任何臨時變量,
new HTTPRequest(new Uri(“https://google.com”), (request, response) =>Debug.Log(“Finished!”)).Send();
POST Requests
上面的例子是一些簡單的Get請求,如果我們不指定方法,所有的的請求都會默認是Get請求。構造函數含有一個可以指定請求方法的參數:
1 HTTPRequest request = new HTTPRequest(new Uri(“yourserver.com/posturi”), 2 HTTPMethods.Post, 3 OnRequestFinished); 4 request.AddField(“FieldName”, “Field Value”); 5 request.Send();
想要Post任何數據而不想設置域的話,你可以使用RawData屬性。
1 HTTPRequest request = new HTTPRequest(new Uri(“yourserver.com/posturi”),HTTPMethods.Post,OnRequestFinished); 4 request.RawData = Encoding.UTF8.GetBytes("Field Value"); 5 request.Send();
除了GET和POST方法,其他方法也可以同樣的使用。
如何獲取下載的數據
通常我們都會通過請求來獲取服務器的一些數據,原始的字節數據可以通過HTTPResponse 對象的Data屬性獲得,我們來看一個下載圖片的例子:
1 new HTTPRequest(new Uri(“http://yourserver.com/path/to/image.png”), (request, response) => 2 { 3 var tex = new Texture2D(0, 0); 4 tex.LoadImage(response.Data); 5 guiTexture.texture = tex; 6 }).Send();
當然還有更緊湊的辦法:
new HTTPRequest(new Uri(“http://yourserver.com/path/to/image.png”), (request, response) => guiTexture.texture = response.DataAsTexture2D).Send();
除了DataAsTexture2D 還有一個DataAsText 屬性用來將響應解析成UTF8的字符串。
注意:本文中的所有例子都沒有進行錯誤檢查,請在生產環境中自己添加判空。
你也可以借助StartCoroutine 來yield HTTPRequest ,
1 HTTPRequest request = new HTTPRequest(new Uri(“http://server.com”)); 2 request.Send(); 3 yield return StartCoroutine(request); 4 Debug.Log(“Request finished! Downloaded Data:” + request.Response.DataAsText);
Debug.Log只會在請求完成后被調用。
高階話題:
下面將會討論BestHttp的一些高階用法
我們可以很容易的通過HTTPRequest 的構造函數開啟或關閉一些特性。下面是這些參數:
● methodType: 決定給服務器發出什么請求。默認的methodType
是HTTPMethods.Get.
● isKeepAlive:告訴服務器我們想 tcp 連接保持開啟, 這樣連續的Htttp請求就不必再次打開連接。 如果我們保持默認開啟,會省下不少時間。 如果我們確信不會那么頻繁的請求,那么可以設為false。 默認值是true.
關於KeepAlive的一些信息:
http://www.cnblogs.com/huangfox/archive/2012/03/31/2426341.html
http://www.cnblogs.com/skynet/archive/2010/12/11/1903347.html
所以別指望這能代替socket的長連接。
● disableCache: 告訴BestHttp系統用或者不用整個緩存機制。如果這個值是true,那么系統不會去緩存里查找已存儲的響應,
而且響應也不會被緩存。 默認值是 false.
驗證系統
BestHTTP 通過HTTPRequest的認證屬性支持基礎和摘要認證:
1 using BestHTTP.Authentication; 2 var request = new HTTPRequest(new Uri("https://httpbin.org/digest-auth/auth-int/usr/paswd"), (req, resp) 3 => 4 { 5 if (resp.StatusCode != 401) 6 Debug.Log("Authenticated"); 7 else 8 Debug.Log("NOT Authenticated"); 9 Debug.Log(resp.DataAsText); 10 }); 11 request.Credentials = new Credentials("usr", "paswd"); 12 request.Send();
關於驗證,可以參考:
http://blog.csdn.net/dyllove98/article/details/9255719
流媒體
我們為HTTPRequest的構造函數提供的回調函數默認只會在服務器響應完全下載完成處理后被調用一次。如果采取這樣的方式的話,在手機設備上下載大文件我們會很快用光內存,應用也就會崩潰。為了避免,BestHTTP 被設計成可以很容易的處理這類問題:只用把一個標志設為true,我們的回調函數會在每一次預定量的數據下載完成后被調用。另外如果我們沒關閉緩存,下載的響應會被緩存,這樣我們就可以從本地緩存獲取整個響應,並且不用該我們的代碼也不用碰服務器。(PS:服務器必須發送正確的頭:headers (“Expires”
header:)
1 var request = new HTTPRequest(new Uri("http://yourserver.com/bigfile"), (req, resp) => 2 { 3 List<byte[]> fragments = resp.GetStreamedFragments(); 4 // Write out the downloaded data to a file: 5 using (FileStream fs = new FileStream("pathToSave", FileMode.Append)) 6 foreach(byte[] data in fragments) 7 fs.Write(data, 0, data.Length); 8 if (resp.IsStreamingFinished) 9 Debug.Log(“Download finished!”); 10 }); 11 request.UseStreaming = true; 12 request.StreamFragmentSize = 1 * 1024 * 1024; // 1 megabyte 13 request.DisableCache = true; // already saving to a file, so turn off caching 14 request.Send();
下面簡要描述一下我們在上面所做的操作
1.我們切換了標志位-UseStreaming為true,所以我們的回調函數可以被反復調用。
2.StreamFragmentSize標示了我們在調用回調函數之前希望緩存的最大數據量。
3.每當StreamFragmentSize 大小的數據塊下載后我們的回調函數就會被調用,並且在IsStreamingFinished 設為true之后還會再調用一次。
4.獲得下載的數據需要調用GetStreamedFragments()函數,我們應該將它的結果保存在臨時變量里,因為內部緩存會在這次調用結束后被清空,所以后續的調用會返回空。
5.我們在這個例子里關閉了緩存,因為我們已經保存了下載的文件,並且我們不希望占據太多的空間。
緩存
緩存也是基於HTTP/1.1 RFC的。它用頭信息來存儲和驗證響應。緩存機制在后台工作,我們只需要決定是否啟用。如果緩存的響應有一個帶有未來時間的’Expires‘頭,BestHTTP 會用緩存的響應而且不會向服務器驗證。這意味着我們不需要初始化任何tcp連接。這能讓我們節省時間、帶寬,並且可以離線使用。
雖然緩存是自動的,我們還是能夠控制一些,或者說我們可以獲得一些信息,通過使用HTTPCacheService 類的一些公共函數:
● BeginClear(): 它會在另外一個線程清除所有的緩存。
● BeginMaintainence(): 通過這個函數,我們可以根據最近的訪問時間刪除緩存的條目。它會刪除最后訪問時間比指定時間早的緩存條目。 我們也可以用這個函數保持緩存大小:
// 刪除在最近兩周沒被訪問的緩存, 然后刪除條目以保持緩存大小在50M以下, 從最早的開始.
HTTPCacheService.BeginMaintainence(new HTTPCacheMaintananceParams(TimeSpan.FromDays(14),
50 * 1024 * 1024));
● GetCacheSize(): 返回緩存大小,字節表示
● GetCacheEntryCount(): 返回存儲在緩存里的條目數. 平均的緩存條目大小可以被這樣計算float avgSize = GetCacheSize() / (float)GetCacheEntryCount() .