标签:lan location ini 更新 version 释放 细节 切换 异步刷新
Release 实现异步更新网络图片 · bajdcc/GameFramework · GitHub
计划着将一些好用的东西整合进框架中,目前用了libevent和libcurl,仅当尝鲜。话说libcurl的使用其实很简单,跟php的curl扩展差不多。libevent是初次使用,很多坑尚未发现。
简单介绍下封面界面的构成:必应背景、一言API、文字、二维码。其中新增的是前二个:必应背景和一言文字。
下面是主要内容:
项目中需要用到libevent,实现异步通知功能。libevent支持网络/文件IO、定时器、信号。在这里,我们只需要用到其中的定时器功能。
vs2015中编译静态库libevent
libevent的简单使用
void msg_timer(evutil_socket_t fd, short event, void *arg) { /*do something...*/ } struct event_base *evbase = event_base_new();//初始化event_base,一线程一个 struct event msgtimer; struct timeval tv; evtimer_assign(&msgtimer, evbase, &msg_timer, NULL);//初始化事件 evutil_timerclear(&tv); tv.tv_sec = 0; tv.tv_usec = 10;//10毫秒后触发事件 evtimer_add(&msgtimer, &tv);//将事件加入到队列中 event_base_dispatch(evbase);//开始处理队列 event_base_free(evbase);//释放
上述例子简单介绍了如何用libevent设置定时事件。
curl和wget是做爬虫的常用工具,它们有很多功能。这里,项目中使用libcurl来下载web上的json。
vs2015中编译静态库libcurl
libcurl的简单使用
static size_t http_get_process(void *data, size_t size, size_t nmemb, std::string &content) { auto sizes = size * nmemb; content += std::string((char*)data, sizes); return sizes; } curl_global_init(CURL_GLOBAL_ALL); CURL *curl = curl_easy_init();//初始化 std::string text;//保存的内容 curl_easy_setopt(curl, CURLOPT_URL, "http://www.baidu.com");//url curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L);//超时,单位秒 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);//自动301、302跳转 curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");//留空表示自动解压 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, TRUE); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &text); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &http_get_process); CURLcode res = curl_easy_perform(curl); if (res == CURLE_OK) { /*text中的内容就是url返回的内容,当然这里面有编码问题,暂且不谈*/ } curl_easy_cleanup(curl); curl_global_cleanup();
那么后面json的下载就要用到curl了。
Win32事件驱动模型
经典的win32程序是基于消息的,程序不断处理操作系统给的消息,总体是单线程的。
//消息处理函数 LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) //主循环 while (GetMessage (&msg, NULL, NULL, NULL)) { TranslateMessage (&msg) ; //翻译消息 DispatchMessage (&msg) ; //分派消息 }
大道至简,一个循环解决问题。一般而言,这么写没问题。但是,如果涉及耗时的操作如网络IO……程序就假死了!
比如想做一个下载器,做一个带界面的爬虫,如果只是单线程处理,那么在下载过程中,win32窗口是无响应的,因为它卡在网络IO上了。为了避免这种情况,只能使用多线程。
有了多线程,也就有了竞争与冲突风险,以及各种线程同步问题,解决这些问题的关键是设计一个好用的、简单的模型。最终的思路必然是简单的,否则出了问题谁也找不出。
异步模型的思考
一般的思路:耗时的操作交给工作线程做,主线程处理窗口的消息。这里用libevent解决。
libevent其实也相当于一个死循环,在这个死循环中,它可以:
注意,它一直在“查看”,也就是说,看看没消息,它就继续干别的事,不会卡死在一个地方。
那么结合win32和libevent,我们有:
这样保证:win32消息的处理和定时器消息的处理处于同一线程中。这个“处于同一线程中”,好处可大了,因为可以避免线程同步等一系列问题。我们在win32主线程中用lua处理各种消息,而lua可以设置定时器;同样地,我们用lua处理定时器消息。换句话说,自始至终,lua都跑在主线程中,跟其他线程无关。
异步下载网络资源
实现了整个框架最为核心的异步事件模型,那么如何解决网络资源下载问题呢?比如说,我想点击按钮,就下载一个json,通过分析json,下载相应的背景图片,并将这个图片作为程序的背景。
目前,libevent的设置定时器功能是可以跨线程调用的,要注意的是只有这里存在跨线程调用。
那么这一流程如下:
以上,打*星号的是其他线程,只有curl所在的thread2是其他线程,其他操作都在主线程中。这个模型也是实现题图效果的关键。
不是说实现了模型就能运行程序了,上得了厅堂、下得了厨房,还有些细节需要考虑。
编码问题
默认的std::string是GBK编码的,而一般的json文件是UTF-8,需要转码。
在curl中,我们用
char *content_type;
curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type);
如果content_type中有UTF-8出现,那么文件编码就是UTF8。
第一步:先用curl下载byte[]二进制数据
size_t http_get_process_bin(void *data, size_t size, size_t nmemb, std::vector<byte> &content) { auto sizes = size * nmemb; auto bin = (byte*)data; for (size_t i = 0; i < sizes; ++i) { content.push_back(bin[i]); } return sizes; } auto bindata = new std::vector<byte>(); curl_easy_setopt(curl, CURLOPT_WRITEDATA, bindata); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &http_get_process_bin); /*其他的设置以及curl_easy_perform都省略了*/
将数据存到std::vector<byte>中。
第二步:转码,UTF8 to GBK
CString Utf8ToStringT(LPCSTR str) { _ASSERT(str); USES_CONVERSION; WCHAR *buf; int length = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0); buf = new WCHAR[length + 1]; ZeroMemory(buf, (length + 1) * sizeof(WCHAR)); MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, length); return (CString(W2T(buf))); } auto gbk = CStringA(content_type);//gbk相当于std::string
其中CString是ATL中的unicode字符串。将CString自行转换至CStringA,而CStringA是ANSI编码的。
如何呈现网上下载的图片
先用libcurl下载二进制图片数据std::vector<byte> data,我们需要用一个byte[]类型去呈现它。
data首先存放在libcurl所在线程中,最终调用者却是渲染图元ImageElement位于主线程中的渲染事件中,两者相距太远,如何联络?
我采取的解决方法是:
由https://zhuanlan.zhihu.com/p/25476629备份。
标签:lan location ini 更新 version 释放 细节 切换 异步刷新
原文地址:https://www.cnblogs.com/bajdcc/p/8972932.html