cocos2d-x 10.1版本 http 链接

这是根据 cocos2d-x-2.0 修改的。

 

 1 /********************************************************************
 2  *  Copyright(C) 2012 Ambition( All rights reserved. )
 3  *    Created:    2012/09/18   11:21
 4  *    File base:    HSBaseHttp.h
 5  *    Author:        Ambition
 6  *    
 7  *    Purpose:    
 8 *********************************************************************/
 9 #ifndef __HSBaseHttp_H__
10 #define __HSBaseHttp_H__
11 #pragma once
12 #include "cocos2d.h"
13 #include "curl.h"
14 #include <queue>
15 #include <pthread.h>
16 #include <semaphore.h>
17 #include <errno.h>
18 #include "HSHttpRequest.h"
19 #include "HSHttpResponse.h"
20 using namespace cocos2d;
21 
22 #if WIN32
23 #pragma comment(lib,"libcurl_imp.lib")
24 #pragma comment(lib,"pthreadVCE2.lib")
25 #endif
26 
27 
28 class HSBaseHttp : public SelectorProtocol,public CCObject
29 {
30 
31 public:
32     HSBaseHttp();
33     virtual ~HSBaseHttp();
34 
35 private:
36     int iTimeoutForConnect;        //链接超时时间
37     int iTimeoutForRead;        //读取超时时间
38 public:
39     //得到一个实例
40     static HSBaseHttp* GetInstance();
41     //销毁实例
42     static void DestroyInstance();
43     //发送请求
44     void Send(HSHttpRequest* request);
45     void SetTimeoutForConnect(int value);
46     
47     int GetTimeoutForConnect();
48  
49     void SetTimeoutForRead(int value);
50 
51     int GetTimeoutForRead();
52     
53 
54 
55 private:
56     //销毁回调
57     void DispatchResponseCallbacks(float delta);
58     //线程信号初始化
59     bool LazyInitThreadSemphore();
60 };
61 
62 
63 #endif // __HSBaseHttp_H__

 

  1 #include "HSBaseHttp.h"
  2 
  3 
  4 //static member
  5 static HSBaseHttp* s_pBaseHttp = NULL; // pointer to singleton
  6 
  7 //线程锁
  8 static pthread_t        s_networkThread;
  9 static pthread_mutex_t  s_requestQueueMutex;
 10 static pthread_mutex_t  s_responseQueueMutex;
 11 static sem_t *          s_pSem = NULL;
 12 static unsigned long    s_asyncRequestCount = 0;
 13 
 14 static bool need_quit = false;
 15 static CCArray* s_requestQueue = NULL;        //请求队列
 16 static CCArray* s_responseQueue = NULL;        //响应队列
 17 
 18 #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
 19 #define CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE 1
 20 #else
 21 #define CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE 0
 22 #endif
 23 
 24 #if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE
 25 #define CC_ASYNC_HTTPREQUEST_SEMAPHORE "ccHttpAsync"
 26 #else
 27 static sem_t s_sem;
 28 #endif
 29 
 30 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
 31 typedef int int32_t;
 32 #endif
 33 
 34 static char s_errorBuffer[CURL_ERROR_SIZE];
 35 
 36 typedef size_t (*write_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
 37 
 38 //////////////////////////////////////////////////////////////////////////
 39 // C 函数实现
 40 //////////////////////////////////////////////////////////////////////////
 41 
 42 size_t writeData(void *ptr, size_t size, size_t nmemb, void *stream)
 43 {
 44     std::vector<char> *recvBuffer = (std::vector<char>*)stream;
 45     size_t sizes = size * nmemb;
 46 
 47     recvBuffer->clear();
 48     recvBuffer->assign((char*)ptr, (char*)ptr + sizes);
 49     CCLog("...%s ...   ",(char*)ptr);
 50 
 51     return sizes;
 52 }
 53 
 54 bool ConfigureCURL(CURL *handle)
 55 {
 56     if (!handle) {
 57         return false;
 58     }
 59 
 60     int32_t code;
 61     code = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, s_errorBuffer);
 62     if (code != CURLE_OK) {
 63         return false;
 64     }
 65     //设置超时时间 防止一直等待
 66     code = curl_easy_setopt(handle, CURLOPT_TIMEOUT, HSBaseHttp::GetInstance()->GetTimeoutForRead());
 67     if (code != CURLE_OK) {
 68         return false;
 69     }
 70     code = curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, HSBaseHttp::GetInstance()->GetTimeoutForConnect());
 71     if (code != CURLE_OK) {
 72         return false;
 73     }
 74 
 75     return true;
 76 }
 77 
 78 //Post 模式设置
 79 int ProcessPostTask(HSHttpRequest *request, write_callback callback, void *stream, int32_t *responseCode)
 80 {
 81     CURLcode code = CURL_LAST;
 82     CURL *curl = curl_easy_init();
 83 
 84     do {
 85         if (!ConfigureCURL(curl)) {
 86             break;
 87         }
 88 
 89         code = curl_easy_setopt(curl, CURLOPT_URL, request->GetUrl());
 90         if (code != CURLE_OK) {
 91             break;
 92         }
 93         code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
 94         if (code != CURLE_OK) {
 95             break;
 96         }
 97         code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, stream);
 98         if (code != CURLE_OK) {
 99             break;
100         }
101         code = curl_easy_setopt(curl, CURLOPT_POST, 1);
102         if (code != CURLE_OK) {
103             break;
104         }
105         code = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request->GetRequestData());
106         if (code != CURLE_OK) {
107             break;
108         }
109         code = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request->GetRequestDataSize());
110         if (code != CURLE_OK) {
111             break;
112         }
113         code = curl_easy_perform(curl);
114         if (code != CURLE_OK) {
115             break;
116         }
117 
118         code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, responseCode); 
119         if (code != CURLE_OK || *responseCode != 200) {
120             code = CURLE_HTTP_RETURNED_ERROR;
121         }
122     } while (0);
123     if (curl) {
124         curl_easy_cleanup(curl);
125     }
126 
127     return (code == CURLE_OK ? 0 : 1);    
128 }
129 
130 //Get模式设置
131 int ProcessGetTask(HSHttpRequest *request, write_callback callback, void *stream, int *responseCode)
132 {
133     CURLcode code = CURL_LAST;
134     CURL *curl = curl_easy_init();
135 
136     do {
137         if (!ConfigureCURL(curl)) 
138         {
139             break;
140         }
141 
142         code = curl_easy_setopt(curl, CURLOPT_URL, request->GetUrl());
143         if (code != CURLE_OK) 
144         {
145             break;
146         }
147 
148         code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
149         if (code != CURLE_OK) 
150         {
151             break;
152         }
153 
154         code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, stream);
155         if (code != CURLE_OK) 
156         {
157             break;
158         }
159 
160         code = curl_easy_perform(curl);
161         if (code != CURLE_OK) 
162         {
163             break;
164         }
165 
166         code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, responseCode); 
167         if (code != CURLE_OK || *responseCode != 200) 
168         {
169             code = CURLE_HTTP_RETURNED_ERROR;
170         }
171     } while (0);
172 
173     if (curl) {
174         curl_easy_cleanup(curl);
175     }
176 
177     return (code == CURLE_OK ? 0 : 1);
178 }
179 
180 
181 static void* NetworkThread(void *data)
182 {    
183     HSHttpRequest *request = NULL;
184 
185     while (true) 
186     {
187         // Wait for http request tasks from main thread
188         int semWaitRet = sem_wait(s_pSem);
189         if (semWaitRet < 0) {
190             CCLog("HSBaseHttp: HttpRequest async thread semaphore error: %s\n", strerror(errno));
191             break;
192         }
193 
194         if (need_quit)
195         {
196             break;
197         }
198 
199         // step 1: send http request if the requestQueue isn't empty
200         request = NULL;
201 
202         pthread_mutex_lock(&s_requestQueueMutex); //Get request task from queue
203         if (0 != s_requestQueue->count())
204         {
205             request = dynamic_cast<HSHttpRequest*>(s_requestQueue->objectAtIndex(0));
206             s_requestQueue->removeObjectAtIndex(0);  
207             // request's refcount = 1 here
208         }
209         pthread_mutex_unlock(&s_requestQueueMutex);
210 
211         if (NULL == request)
212         {
213             continue;
214         }
215 
216         // step 2: libcurl sync access
217 
218         // Create a HttpResponse object, the default setting is http access failed
219         HSHttpResponse *response = new HSHttpResponse(request);
220 
221         // request's refcount = 2 here, it's retained by HttpRespose constructor
222         request->release();
223         // ok, refcount = 1 now, only HttpResponse hold it.
224 
225         int responseCode = -1;
226         int retValue = 0;
227 
228         // Process the request -> get response packet
229         switch (request->GetRequestType())
230         {
231         case HSHttpRequest::HTTP_MODE_GET: // HTTP GET
232             retValue = ProcessGetTask(request,     writeData,     response->GetResponseData(), &responseCode);
233             break;
234 
235         case HSHttpRequest::HTTP_MODE_POST: // HTTP POST
236             retValue = ProcessPostTask(request, writeData,     response->GetResponseData(), &responseCode);
237             break;
238 
239         default:
240             CCAssert(true, "CCHttpClient: unkown request type, only GET and POSt are supported");
241             break;
242         }
243 
244         // write data to HttpResponse
245         response->SetResponseCode(responseCode);
246 
247         if (retValue != 0) 
248         {
249             response->SetSucceed(false);
250             response->SetErrorBuffer(s_errorBuffer);
251         }
252         else
253         {
254             response->SetSucceed(true);
255         }
256 
257 
258         // add response packet into queue
259         pthread_mutex_lock(&s_responseQueueMutex);
260         s_responseQueue->addObject(response);
261         pthread_mutex_unlock(&s_responseQueueMutex);
262 
263         // resume dispatcher selector
264         CCScheduler::sharedScheduler()->resumeTarget(HSBaseHttp::GetInstance());
265     }
266 
267     // cleanup: if worker thread received quit signal, clean up un-completed request queue
268     pthread_mutex_lock(&s_requestQueueMutex);
269     s_requestQueue->removeAllObjects();
270     pthread_mutex_unlock(&s_requestQueueMutex);
271     s_asyncRequestCount -= s_requestQueue->count();
272 
273     if (s_pSem != NULL) {
274 #if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE
275         sem_unlink(CC_ASYNC_HTTPREQUEST_SEMAPHORE);
276         sem_close(s_pSem);
277 #else
278         sem_destroy(s_pSem);
279 #endif
280 
281         s_pSem = NULL;
282 
283         pthread_mutex_destroy(&s_requestQueueMutex);
284         pthread_mutex_destroy(&s_responseQueueMutex);
285 
286         s_requestQueue->release();
287         s_responseQueue->release();
288     }
289 
290     pthread_exit(NULL);
291 
292     return 0;
293 }
294 
295 HSBaseHttp::HSBaseHttp()
296 {
297     this->iTimeoutForConnect = 30;
298     this->iTimeoutForRead = 60;
299     CCScheduler::sharedScheduler()->scheduleSelector(schedule_selector(HSBaseHttp::DispatchResponseCallbacks), this, 0, false);
300     CCScheduler::sharedScheduler()->pauseTarget(this);
301 }
302 
303 HSBaseHttp::~HSBaseHttp()
304 {
305     need_quit = true;
306 
307     if (s_pSem != NULL) 
308     {
309         sem_post(s_pSem);
310     }
311     CCScheduler::sharedScheduler()->unscheduleSelector(schedule_selector(HSBaseHttp::DispatchResponseCallbacks), this);
312 }
313 
314 HSBaseHttp* HSBaseHttp::GetInstance()
315 {
316     if (s_pBaseHttp == NULL)
317     {
318         s_pBaseHttp = new HSBaseHttp();
319     }
320 
321     return s_pBaseHttp;
322 }
323 
324 void HSBaseHttp::DestroyInstance()
325 {
326     CCScheduler::sharedScheduler()->unscheduleSelector(schedule_selector(HSBaseHttp::DispatchResponseCallbacks),HSBaseHttp::GetInstance());
327     CC_SAFE_RELEASE_NULL(s_pBaseHttp);
328 }
329 
330 void HSBaseHttp::DispatchResponseCallbacks(float delta)
331 {
332     HSHttpResponse* response = NULL;
333 
334     pthread_mutex_lock(&s_responseQueueMutex);
335     if (s_responseQueue->count())
336     {
337         response = dynamic_cast<HSHttpResponse*>(s_responseQueue->objectAtIndex(0));
338         s_responseQueue->removeObjectAtIndex(0);
339     }
340     pthread_mutex_unlock(&s_responseQueueMutex);
341 
342     if (response)
343     {
344         --s_asyncRequestCount;
345 
346         HSHttpRequest* request = response->GetHttpRequest();
347         SelectorProtocol* pTarget = request->GetTarget();
348         SEL_CallFuncND pSelector = request->GetSelector();
349 
350         if (pTarget && pSelector) 
351         {
352             (pTarget->*pSelector)((CCNode *)this, response);
353         }
354 
355         response->release();
356     }
357 
358     if (0 == s_asyncRequestCount) 
359     {
360         CCScheduler::sharedScheduler()->pauseTarget(this);
361     }
362 }
363 
364 bool HSBaseHttp::LazyInitThreadSemphore()
365 {
366     if(s_pSem != NULL)
367         return false;
368 
369 #if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE
370     s_pSem = sem_open(CC_ASYNC_HTTPREQUEST_SEMAPHORE, O_CREAT, 0644, 0);
371     if (s_pSem == SEM_FAILED) {
372         CCLog("Open HttpRequest Semaphore failed");
373         s_pSem = NULL;
374         return false;
375     }
376 #else
377     int semRet = sem_init(&s_sem, 0, 0);
378     if (semRet < 0) {
379         CCLog("Init HttpRequest Semaphore failed");
380         return false;
381     }
382 
383     s_pSem = &s_sem;
384 #endif
385 
386     s_requestQueue = CCArray::array();
387     s_requestQueue->init();
388     s_requestQueue->retain();
389 
390     s_responseQueue = CCArray::array();    
391     s_responseQueue->init();
392     s_responseQueue->retain();
393 
394     pthread_mutex_init(&s_requestQueueMutex, NULL);
395     pthread_mutex_init(&s_responseQueueMutex, NULL);
396 
397     pthread_create(&s_networkThread, NULL, NetworkThread, NULL);
398     pthread_detach(s_networkThread);
399 
400     need_quit = false;
401 
402     return true;
403 
404 }
405 
406 void HSBaseHttp::Send(HSHttpRequest* request)
407 {
408     if (!LazyInitThreadSemphore() || !request) 
409     {
410         return;
411     }
412 
413     ++s_asyncRequestCount;
414 
415     request->retain();
416 
417     pthread_mutex_lock(&s_requestQueueMutex);
418     s_requestQueue->addObject(request);
419     pthread_mutex_unlock(&s_requestQueueMutex);
420 
421     // Notify thread start to work
422     sem_post(s_pSem);
423 }
424 
425 void HSBaseHttp::SetTimeoutForConnect( int value )
426 {
427     this->iTimeoutForConnect = value;
428 }
429 
430 int HSBaseHttp::GetTimeoutForConnect()
431 {
432     return this->iTimeoutForConnect;
433 }
434 
435 void HSBaseHttp::SetTimeoutForRead( int value )
436 {
437     this->iTimeoutForRead = value;
438 }
439 
440 int HSBaseHttp::GetTimeoutForRead()
441 {
442     return this->iTimeoutForRead;
443 }

 

 

 1 /********************************************************************
 2  *  Copyright(C) 2012 Ambition( All rights reserved. )
 3  *    Created:    2012/09/20   9:41
 4  *    File base:    HSHttpRequest.h
 5  *    Author:        Ambition
 6  *    
 7  *    Purpose:    请求消息发送和设置(不是发送的具体数据)
 8 *********************************************************************/
 9 #ifndef __HSHttpRequest_H__
10 #define __HSHttpRequest_H__
11 #pragma once
12 #include "cocos2d.h"
13 using namespace cocos2d;
14 
15 class HSHttpRequest : public CCObject
16 {
17 public:
18     HSHttpRequest(void);
19     ~HSHttpRequest(void);
20 
21 public:
22     typedef enum
23     {
24         HTTP_MODE_GET,
25         HTTP_MODE_POST,
26         HTTP_MODE_UNKOWN,
27     }HttpRequestType;
28 
29 protected:
30     SelectorProtocol*    pTarget;
31     SEL_CallFuncND        pSelector;        //回调选择器
32     HttpRequestType        requestType;    //请求类型
33     string                strUrl;
34     vector<char>        vRequestData;
35     string              tag;
36     void*               pUserData;        //用语在请求前添加的标志 例(Ambition:xxxxxx)
37 
38 public:
39     SelectorProtocol* GetTarget();
40     SEL_CallFuncND GetSelector();
41     void SetRequestType(HttpRequestType type);
42     HttpRequestType GetRequestType();
43 
44     void SetUrl(const char* url);
45     const char* GetUrl();
46 
47     void SetRequestData(const char* buffer, unsigned int len);
48     char* GetRequestData();
49 
50     int GetRequestDataSize();
51 
52     void SetResponseCallback(SelectorProtocol* pTarget, cocos2d::SEL_CallFuncND pSelector);  
53 
54     void SetTag(const char* tag);
55     const char* GetTag();
56 
57     void SetUserData(void* pUserData);
58     void* GetUserData();
59 };
60 
61 
62 #endif // __HSHttpRequest_H__

 

 

 1 #include "HSHttpRequest.h"
 2 
 3 HSHttpRequest::HSHttpRequest(void)
 4 {
 5     this->requestType = HTTP_MODE_UNKOWN;
 6     this->vRequestData.clear();
 7     this->tag.clear();
 8     this->pTarget = NULL;
 9     this->pSelector = NULL;
10     this->pUserData = NULL;
11 }
12 
13 HSHttpRequest::~HSHttpRequest(void)
14 {
15 }
16 
17 SelectorProtocol* HSHttpRequest::GetTarget()
18 {
19     return this->pTarget;
20 }
21 
22 cocos2d::SEL_CallFuncND HSHttpRequest::GetSelector()
23 {
24     return pSelector;
25 }
26 
27 HSHttpRequest::HttpRequestType HSHttpRequest::GetRequestType()
28 {
29     return this->requestType;
30 }
31 
32 void HSHttpRequest::SetUrl( const char* url )
33 {
34     strUrl = url;
35 }
36 
37 const char* HSHttpRequest::GetUrl()
38 {
39     return strUrl.c_str();
40 }
41 
42 void HSHttpRequest::SetRequestData( const char* buffer, unsigned int len )
43 {
44     vRequestData.assign(buffer, buffer + len);
45 }
46 
47 char* HSHttpRequest::GetRequestData()
48 {
49     return &(vRequestData.front());
50 }
51 
52 int HSHttpRequest::GetRequestDataSize()
53 {
54     return vRequestData.size();
55 }
56 
57 void HSHttpRequest::SetRequestType( HttpRequestType type )
58 {
59     requestType = type;
60 }
61 
62 void HSHttpRequest::SetResponseCallback( SelectorProtocol* pTarget, cocos2d::SEL_CallFuncND pSelector )
63 {
64     this->pTarget = pTarget;
65     this->pSelector = pSelector;
66 
67     if (this->pTarget)
68     {
69         //this->pTarget->retain();
70         //如果有问题以后修改
71     }
72 }
73 
74 void HSHttpRequest::SetTag( const char* tag )
75 {
76     this->tag = tag;
77 }
78 
79 const char* HSHttpRequest::GetTag()
80 {
81     return this->tag.c_str();
82 }
83 
84 void HSHttpRequest::SetUserData( void* pUserData )
85 {
86     this->pUserData = pUserData;
87 }
88 
89 void* HSHttpRequest::GetUserData()
90 {
91     return this->pUserData;
92 }

 

 1 /********************************************************************
 2  *  Copyright(C) 2012 Ambition( All rights reserved. )
 3  *    Created:    2012/09/20   9:42
 4  *    File base:    HSHttpResponse.h
 5  *    Author:        Ambition
 6  *    
 7  *    Purpose:    响应包含返回的具体数据,但是没有解析
 8 *********************************************************************/
 9 #ifndef __HSHttpResponse_H__
10 #define __HSHttpResponse_H__
11 #pragma once
12 #include "HSHttpRequest.h"
13 
14 
15 class HSHttpResponse : public CCObject
16 {
17 public:
18     HSHttpResponse(HSHttpRequest* request);
19     virtual ~HSHttpResponse(void);
20 
21 protected:
22     HSHttpRequest*    pHttpRequest;    //对应的请求指针
23     bool            isSucceed;        //是否成功
24     vector<char>    vResponseData;    
25     int                iResponseCode;    //响应代码
26     string            strErrorBuffer;    //错误信息缓存
27 
28 public:
29     HSHttpRequest* GetHttpRequest();
30 
31     void SetResponseData(std::vector<char>* data);
32     vector<char>* GetResponseData();
33 
34     void SetResponseCode(int value);
35     int GetResponseCode();
36 
37     void SetSucceed(bool value);
38     bool GetSucceed();
39 
40     void SetErrorBuffer(const char* value);
41     const char* GetErrorBuffer();
42 
43 };
44 
45 #endif // __HSHttpResponse_H__

 

 1 #include "HSHttpResponse.h"
 2 
 3 HSHttpResponse::HSHttpResponse(HSHttpRequest* request)
 4 {
 5     this->pHttpRequest = request;
 6     if (this->pHttpRequest)
 7     {
 8         this->pHttpRequest->retain();
 9     }
10     this->isSucceed = false;
11     this->vResponseData.clear();
12     this->strErrorBuffer.clear();
13 }
14 
15 HSHttpResponse::~HSHttpResponse(void)
16 {
17     if (this->pHttpRequest)
18     {
19         this->pHttpRequest->release();
20     }
21 }
22 
23 HSHttpRequest* HSHttpResponse::GetHttpRequest()
24 {
25     return this->pHttpRequest;
26 }
27 
28 void HSHttpResponse::SetResponseData( std::vector<char>* data )
29 {
30     vResponseData = *data;
31 }
32 
33 vector<char>* HSHttpResponse::GetResponseData()
34 {
35     return &vResponseData;
36 }
37 
38 void HSHttpResponse::SetResponseCode( int value )
39 {
40     iResponseCode = value;
41 }
42 
43 int HSHttpResponse::GetResponseCode()
44 {
45     return this->iResponseCode;
46 }
47 
48 void HSHttpResponse::SetSucceed( bool value )
49 {
50     isSucceed = value;
51 }
52 
53 bool HSHttpResponse::GetSucceed()
54 {
55     return this->isSucceed;
56 }
57 
58 void HSHttpResponse::SetErrorBuffer( const char* value )
59 {
60     strErrorBuffer.clear();
61     strErrorBuffer.assign(value);
62 }
63 
64 const char* HSHttpResponse::GetErrorBuffer()
65 {
66     return strErrorBuffer.c_str();
67 }

 

测试代码:

 

 

 1     HSHttpRequest* request = new HSHttpRequest();
 2     request->SetUrl("http://220.194.62.22/wapgame/a.jsp");
 3     request->SetRequestType(HSHttpRequest::HTTP_MODE_POST);
 4     request->SetResponseCallback(this, callfuncND_selector(HelloWorld::onHttpRequestCompleted));
 5 
 6     // write the post data
 7     const char* postData = "visitor=cocos2d&TestSuite=Extensions Test/NetowrkTest";
 8     request->SetRequestData(postData, strlen(postData)); 
 9     request->SetTag("POST test");
10     HSBaseHttp::GetInstance()->Send(request);
11     request->release();

 

posted on 2012-09-28 08:58  游戏开发:主席  阅读(4183)  评论(0编辑  收藏  举报

导航