CefPostTask
概述
- 用于在特定线程上调度任务的方法
- 它允许你将任务(通常是函数或回调)推送到
CEF
的某个内部线程进行异步执行- 这样,你可以避免在不合适的线程上执行操作,从而确保线程安全并优化性能
线程类型
TID_UI
UI
线程,处理用户界面相关的任务
TID_IO
IO
线程,处理网络和文件IO
操作
TID_RENDERER
- 渲染线程,处理页面渲染任务(通常在渲染进程中使用)
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include "include/cef_task.h" // 一个简单的任务示例 void MyTask() { std::cout << "Task executed on thread: " << CefCurrentlyOn(TID_UI) << std::endl; } // 调度任务到UI线程 void PostTaskToUIThread() { CefPostTask(TID_UI, base::BindOnce(&MyTask)); } // 调度任务到IO线程 void PostTaskToIOThread() { CefPostTask(TID_IO, base::BindOnce(&MyTask)); } int main() { CefMainArgs main_args; CefRefPtr<MyApp> app(new MyApp()); CefInitialize(main_args, CefSettings(), app, nullptr); // 在主线程上调度任务到UI线程和IO线程 PostTaskToUIThread(); PostTaskToIOThread(); CefRunMessageLoop(); CefShutdown(); return 0; } |
CefTaskRunner
- 用于管理任务的调度和执行
- 它提供了一种在特定线程上调度任务的方法,类似于
CefPostTask
,但CefTaskRunner
提供了更多的功能和灵活性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include "include/cef_task.h" #include "include/wrapper/cef_closure_task.h" // 一个简单的任务示例 void MyTask() { std::cout << "Task executed on thread: " << CefCurrentlyOn(TID_UI) << std::endl; } void PostTaskToUIThread() { // 获取 UI 线程的 CefTaskRunner 实例 CefRefPtr<CefTaskRunner> task_runner = CefTaskRunner::GetForThread(TID_UI); // 将任务调度到 UI 线程 task_runner->PostTask(CefCreateClosureTask(base::BindOnce(&MyTask))); } void PostDelayedTaskToUIThread() { // 获取 UI 线程的 CefTaskRunner 实例 CefRefPtr<CefTaskRunner> task_runner = CefTaskRunner::GetForThread(TID_UI); // 将延时任务调度到 UI 线程 task_runner->PostDelayedTask(CefCreateClosureTask(base::BindOnce(&MyTask)), 1000); // 1000 毫秒延迟 } int main() { CefMainArgs main_args; CefRefPtr<MyApp> app(new MyApp()); CefInitialize(main_args, CefSettings(), app, nullptr); // 在主线程上调度任务到UI线程和延时任务到UI线程 PostTaskToUIThread(); PostDelayedTaskToUIThread(); CefRunMessageLoop(); CefShutdown(); return 0; } |
任务队列
- 每个线程(如
UI
线程、IO
线程)都有一个自己的任务队列,这些队列由CEF
的任务调度机制管理
处理异步任务
- 可以将回调函数作为任务的一部分传递,任务执行完毕后调用回调函数处理结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include "include/cef_task.h" #include "include/wrapper/cef_closure_task.h" #include <iostream> #include <functional> // 模拟异步任务 void AsyncTask(std::function<void(int)> callback) { int result = 42; // 假设这是计算或处理后的结果 callback(result); // 调用回调函数并传递结果 } // 处理结果的回调函数 void OnTaskComplete(int result) { std::cout << "Task completed with result: " << result << std::endl; } void PostTaskToUIThread() { CefPostTask(TID_UI, base::BindOnce([]() { AsyncTask(OnTaskComplete); })); } int main() { CefMainArgs main_args; CefRefPtr<MyApp> app(new MyApp()); CefInitialize(main_args, CefSettings(), app, nullptr); // 发布任务到UI线程 PostTaskToUIThread(); CefRunMessageLoop(); CefShutdown(); return 0; } |
- 可以使用共享状态对象(如
std::promise
和std::future
)在不同线程之间传递任务结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include "include/cef_task.h" #include "include/wrapper/cef_closure_task.h" #include <iostream> #include <future> // 模拟异步任务 void AsyncTask(std::promise<int>&& promise) { int result = 42; // 假设这是计算或处理后的结果 promise.set_value(result); // 设置结果 } void PostTaskToUIThread() { std::promise<int> promise; std::future<int> future = promise.get_future(); CefPostTask(TID_UI, base::BindOnce(&AsyncTask, std::move(promise))); // 等待并获取结果 int result = future.get(); std::cout << "Task completed with result: " << result << std::endl; } int main() { CefMainArgs main_args; CefRefPtr<MyApp> app(new MyApp()); CefInitialize(main_args, CefSettings(), app, nullptr); // 发布任务到UI线程 PostTaskToUIThread(); CefRunMessageLoop(); CefShutdown(); return 0; } |
进程间通信
概述
- 用于在浏览器进程和渲染进程之间交换数据和指令
通信方法
- 消息传递
- CEF 提供了消息传递机制,允许进程之间发送和接收自定义消息
- 这种方式通常用于在浏览器进程和渲染进程之间交换数据或通知
v8 javascript
绑定CEF
允许你将C++
对象绑定到JavaScript
环境中,从而使渲染进程能够调用C++
方法- 这种方式可以用于实现复杂的通信逻辑
- 共享数据结构
- 可以使用共享内存或其他共享数据结构在进程之间共享数据
- 这种方法通常更复杂,需要小心管理同步和数据一致性
消息传递机制
- 在
browser
和renderer
进程中定义要传递的消息 - 使用
CefProcessMessage
在一个进程中创建消息,并使用CefBrowser::SendProcessMessage
发送到另一个进程 - 在接收端实现
CefMessageRouterBrowserSide::Handler
或CefMessageRouterRendererSide::Handler
,并在OnProcessMessageReceived
中处理接收到的消息
1 |
const char kMyMessageName[] = "MyMessage"; |
1 2 3 4 5 |
// 在浏览器进程中 CefRefPtr<CefBrowser> browser = ...; // 获取当前浏览器实例 CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(kMyMessageName); message->GetArgumentList()->SetString(0, "Hello from browser process"); browser->SendProcessMessage(PID_RENDERER, message); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 在渲染进程中 class MyRenderProcessHandler : public CefRenderProcessHandler { public: virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) override { if (message->GetName() == kMyMessageName) { CefString msg = message->GetArgumentList()->GetString(0); std::cout << "Received message: " << msg.ToString() << std::endl; return true; } return false; } IMPLEMENT_REFCOUNTING(MyRenderProcessHandler); }; |
v8 javascript
绑定
- 在渲染进程中绑定
C++
对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
class MyV8Handler : public CefV8Handler { public: virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) override { if (name == "myFunction") { std::cout << "myFunction called from JavaScript" << std::endl; retval = CefV8Value::CreateString("Hello from C++"); return true; } return false; } IMPLEMENT_REFCOUNTING(MyV8Handler); }; class MyRenderProcessHandler : public CefRenderProcessHandler { public: virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) override { CefRefPtr<CefV8Value> global = context->GetGlobal(); CefRefPtr<CefV8Handler> handler = new MyV8Handler(); CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myFunction", handler); global->SetValue("myFunction", func, V8_PROPERTY_ATTRIBUTE_NONE); } IMPLEMENT_REFCOUNTING(MyRenderProcessHandler); }; |
- 在
javascript
里面调用C++
方法
1 |
console.log(myFunction()); // Output: "Hello from C++" |
- 基于
CEF
的应用程序还可以提供自己的异步JavaScript
绑定的自定义实现:- 文档
进程启动消息
- 启动数据可以在创建时通过
CefRefPtr<CefDictionaryValue> extra_info
CefBrowserHost::CreateBrowser
的参数与特定的CefBrowser
实例关联 - 该
extra_info
数据将通过CefRenderProcessHandler::OnBrowserCreated
回调传递到与该CefBrowser
关联的每个渲染器进程 - 有关何时以及如何生成新渲染器进程的更多信息,请参阅“进程”部分
网络层
概述
- 默认情况下,
CEF3
中的网络请求将以与主机应用程序透明的方式处理 - 对于希望与网络层建立更紧密关系的应用程序,
CEF3
暴露了一系列与网络相关的功能
URLRequest
- 通过
CefURLRequest
类,可以在应用程序中创建和管理网络请求 - 开发者可以使用这个接口手动发起网络请求,并监听请求的状态和响应数据
请求拦截
CEF
允许开发者在浏览器进程和渲染进程中拦截和修改网络请求- 可以通过实现
CefRequestHandler
接口,在请求发起前或者响应返回后对请求进行处理
Cookie 和缓存管理
CEF
提供了管理Cookie
和缓存的功能,可以通过相应的接口控制Cookie
的设置和删除,以及管理缓存的行为
代理设置
CEF
允许开发者配置代理服务器,以便在网络请求中使用代理- 可以通过
CefRequestContext
和CefRequestContextHandler
设置全局或者特定请求的代理
跨域请求
CEF
支持跨域请求,并且提供了相应的安全机制来控制跨域请求的行为- 跨域请求(
Cross-Origin Request
)是指在Web
开发中,一个网页的脚本向另一个域名(或者协议、端口)发起HTTP
请求- 如果请求的目标与当前页面的域不同,就称为跨域请求
- 跨域请求是由浏览器的同源策略(
Same-Origin Policy
)所限制的 - 同源策略是一个安全机制,它限制了一个网页中的
JavaScript
脚本如何与来自不同源的资源进行交互 - 同源策略要求网页脚本只能访问与其来源相同的资源,即同协议、同域名、同端口的资源
- 解决跨域请求的方法:
- 跨域资源共享(
CORS
)
CORS
是一种机制,允许服务器在响应中附加一个头部信息,指示浏览器该如何处理跨域请求
通过在服务器端设置合适的CORS
头部,可以允许指定域的请求跨越同源策略限制 JSONP(JSON with Padding)
JSONP
是一种利用<script>
标签进行跨域请求的方法。通过动态创建<script>
标签,并设置其src
属性为包含JSON
数据的URL
,从而实现跨域请求
JSONP
仅支持GET
请求,并且需要服务器端支持JSONP
回调- 代理服务器
可以在服务器端设置一个代理服务器,允许客户端通过代理服务器发起跨域请求,然后由代理服务器将请求转发到目标服务器,并将响应返回给客户端 - 服务器端设置跨域资源访问
如果你有权限管理服务器端,可以在服务器端设置相应的配置,以允许指定的来源进行跨域请求 WebSocket
协议
使用WebSocket
协议进行通信可以避免同源策略的限制,WebSocket
不受同源策略的限制,可以在不同源之间进行通信- 浏览器插件或扩展
有些浏览器插件或扩展可以用来绕过跨域请求限制,但这种方法可能会存在安全风险,并且不适用于所有情况
- 跨域资源共享(
SSL/TLS支持
CEF
内置了SSL/TLS
支持,能够安全地进行HTTPS
请求,并支持证书验证和安全连接
部分示例
- 简单的加载方式
1 |
browser->GetMainFrame()->LoadURL(some_url); |
- 自定义请求标头或上传更多复杂请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// Create a CefRequest object. CefRefPtr<CefRequest> request = CefRequest::Create(); // Set the request URL. request->SetURL(some_url); // Set the request method. Supported methods include GET, POST, HEAD, DELETE and PUT. request->SetMethod(“POST”); // Optionally specify custom headers. CefRequest::HeaderMap headerMap; headerMap.insert( std::make_pair("X-My-Header", "My Header Value")); request->SetHeaderMap(headerMap); // Optionally specify upload content. // The default “Content-Type” header value is "application/x-www-form-urlencoded". // Set “Content-Type” via the HeaderMap if a different value is desired. const std::string& upload_data = “arg1=val1&arg2=val2”; CefRefPtr<CefPostData> postData = CefPostData::Create(); CefRefPtr<CefPostDataElement> element = CefPostDataElement::Create(); element->SetToBytes(upload_data.size(), upload_data.c_str()); postData->AddElement(element); request->SetPostData(postData); |
- 还可以通过
Cefurlrequest
类发送网络请求- 实现
cefurlrequestclient
接口以处理结果响应
- 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
class MyRequestClient : public CefURLRequestClient { public: MyRequestClient() : upload_total_(0), download_total_(0) {} void OnRequestComplete(CefRefPtr<CefURLRequest> request) override { CefURLRequest::Status status = request->GetRequestStatus(); CefURLRequest::ErrorCode error_code = request->GetRequestError(); CefRefPtr<CefResponse> response = request->GetResponse(); // Do something with the response... } void OnUploadProgress(CefRefPtr<CefURLRequest> request, int64 current, int64 total) override { upload_total_ = total; } void OnDownloadProgress(CefRefPtr<CefURLRequest> request, int64 current, int64 total) override { download_total_ = total; } void OnDownloadData(CefRefPtr<CefURLRequest> request, const void* data, size_t data_length) override { download_data_ += std::string(static_cast<const char*>(data), data_length); } bool GetAuthCredentials(bool isProxy, const CefString& host, int port, const CefString& realm, const CefString& scheme, CefRefPtr<CefAuthCallback> callback) override { return false; // Not handled. } private: int64 upload_total_; int64 download_total_; std::string download_data_; private: IMPLEMENT_REFCOUNTING(MyRequestClient); }; |
1 2 3 4 5 6 7 8 9 10 |
// Set up the CefRequest object. CefRefPtr<CefRequest> request = CefRequest::Create(); // Populate |request| as shown above... // Create the client instance. CefRefPtr<MyRequestClient> client = new MyRequestClient(); // Start the request. MyRequestClient callbacks will be executed asynchronously. CefRefPtr<CefURLRequest> url_request = CefURLRequest::Create(request, client.get(), nullptr); // To cancel the request: url_request->Cancel(); |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Linux下网络及其他配置相关记述08/12
- ♥ WebSocket协议相关学习一03/24
- ♥ Cef:介绍06/29
- ♥ Base_hash05/25
- ♥ Chromium:学习,框架,一09/02
- ♥ 【LeetCode-30 天 JavaScript 挑战】07/23