【Unity3D插件教程及源码分析】最好用的Http插件BestHttp 【教程上篇】

简介

我用的是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() .

 

posted @ 2015-02-04 17:48  易山松  阅读(13642)  评论(0编辑  收藏  举报