前后端双向IPC通信
JadeView 提供了强大的前后端双向 IPC(进程间通信)机制,允许前端 JavaScript 代码与后端 C/C++ 代码进行高效、安全的双向数据交换。本页面将详细介绍 JadeView 的 IPC 通信原理、使用方法和最佳实践。
什么是 IPC 通信
IPC(Inter-Process Communication,进程间通信)是指不同进程之间进行数据交换的机制。在 JadeView 中,IPC 通信主要用于:
- 前端 JavaScript 代码向后端发送指令或请求数据
- 后端 C/C++ 代码向前端推送事件或数据更新
- 实现前后端之间的双向数据绑定
JadeView IPC 通信的技术原理
JadeView 的 IPC 通信基于以下技术原理:
1. 基于自定义协议的通信机制
JadeView 使用高效的自定义协议实现前后端通信:
- 前端通过
jade.invoke()方法调用后端 API - 消息被序列化后通过本地通信通道发送到后端
- 后端通过注册的回调函数处理请求
- 后端可以通过发送事件向前端推送消息
- 前端通过
jade.on()方法监听后端事件
2. 跨语言序列化与反序列化
为了实现跨语言通信,JadeView 使用 JSON 作为消息序列化格式:
- 前端 JavaScript 直接使用 JSON.stringify() 和 JSON.parse() 进行序列化和反序列化
- 后端 C/C++ 使用内置的 JSON 解析库处理消息
- 支持基本数据类型、对象、数组等复杂数据结构
前端到后端的 IPC 通信
1. 前端调用后端 API
在前端 JavaScript 中,可以通过 jade.invoke() 方法调用后端 API:
有关前端 API 的详细信息,请查看 前端 API 文档。
// 调用后端 API,发送简单数据
async function callBackendAPI() {
try {
const result = await jade.invoke('message-name', { key: 'value' });
console.log('API 调用结果:', result);
} catch (error) {
console.error('API 调用失败:', error);
}
}
// 发送复杂数据
async function updateUser() {
const data = {
user: {
id: 1,
name: 'John Doe'
},
action: 'update_user',
timestamp: Date.now()
};
try {
const result = await jade.invoke('user-update', data);
console.log('用户更新结果:', result);
} catch (error) {
console.error('用户更新失败:', error);
}
}
2. 后端接收请求
在后端 C/C++ 代码中,使用回调函数处理前端请求:
有关 C API 的详细信息,请查看 C API 文档。
#include "jadeview.h"
// 消息处理器回调函数
const char* message_name_callback(uint32_t window_id, const char* event_data) {
printf("收到消息:类型=message-name, 数据=%s\n", event_data);
// 解析 JSON 数据
// 这里可以使用你喜欢的 JSON 解析库
// 返回结果给前端
return "{\"status\": \"success\", \"message\": \"消息处理成功\"}";
}
// 用户更新回调函数
const char* user_update_callback(uint32_t window_id, const char* event_data) {
printf("收到用户更新请求,窗口ID: %u, 数据: %s\n", window_id, event_data);
// 解析并处理用户更新数据
// 返回结果
return "{\"status\": \"success\", \"message\": \"用户更新成功\"}";
}
// 在 app-ready 事件中注册消息处理器
int app_ready_callback(int success, const char* reason) {
if (success == 1 && reason && strcmp(reason, "success") == 0) {
// 注册消息处理器
// 注意:实际注册方式可能根据 API 变化而不同
// 这里仅展示概念
}
return 0;
}
后端到前端的 IPC 通信
1. 后端发送事件
在后端 C/C++ 代码中,使用 send_event() 函数向前端发送事件:
有关 C API 的详细信息,请查看 C API 文档。
#include "jadeview.h"
// 发送简单事件
void send_event_to_frontend(uint32_t window_id) {
// 事件数据
const char* event_data = "{\"status\": \"success\", \"message\": \"操作成功\"}";
// 发送事件到指定窗口
int result = send_event(window_id, "backend-message", event_data);
if (result == 1) {
printf("事件发送成功\n");
} else {
printf("事件发送失败\n");
}
}
// 发送系统更新事件
void send_system_update() {
// 构造事件数据
char event_data[256];
snprintf(event_data, sizeof(event_data),
"{\"type\": \"system\", \"data\": {\"time\": %lld}}",
(long long)time(NULL));
// 发送系统更新事件到所有窗口(窗口ID为0表示广播)
int result = send_event(0, "system-update", event_data);
if (result == 1) {
printf("系统更新事件发送成功\n");
} else {
printf("系统更新事件发送失败\n");
}
}
2. 前端接收事件
在前端 JavaScript 中,使用 jade.on() 方法注册事件处理器:
有关前端 API 的详细信息,请查看 前端 API 文档。
// 接收简单事件
const unsubscribeBackendMsg = jade.on('backend-message', (data) => {
console.log('收到后端消息:', data);
if (data.status === 'success') {
alert('操作成功:' + data.message);
}
});
// 接收系统更新事件
const unsubscribeSystemUpdate = jade.on('system-update', (data) => {
console.log('系统更新:', data);
// 更新页面数据
document.getElementById('system-time').textContent = new Date(data.data.time).toLocaleString();
});
// 当不再需要监听事件时,取消订阅
// unsubscribeBackendMsg();
// unsubscribeSystemUpdate();
完整的 IPC 通信示例
前端 JavaScript 代码
// 发送消息到后端(使用 invoke API)
async function sendMessage(message) {
const data = {
message: message,
timestamp: Date.now()
};
try {
const result = await jade.invoke('frontend-message', data);
console.log('API 调用结果:', result);
} catch (error) {
console.error('API 调用失败:', error);
}
}
// 接收后端事件
const unsubscribeBackendMsg = jade.on('backend-message', (data) => {
console.log('收到后端事件:', data);
// 处理后端事件,例如更新 UI
});
// 接收系统事件
const unsubscribeSystemEvent = jade.on('system-event', (data) => {
console.log('收到系统事件:', data);
// 处理系统事件
});
// 监听页面加载完成
window.addEventListener('load', () => {
// 发送页面加载完成请求
jade.invoke('page-loaded', { status: 'ready' })
.then(result => {
console.log('页面加载确认:', result);
})
.catch(error => {
console.error('页面加载确认失败:', error);
});
});
// 示例:发送一条测试消息
sendMessage('Hello from frontend!');
后端代码
#include "jadeview.h"
#include <stdio.h>
#include <string.h>
#include <time.h>
// 前端消息处理回调
const char* frontend_message_callback(uint32_t window_id, const char* event_data) {
printf("收到前端消息,窗口ID: %u, 数据: %s\n", window_id, event_data);
// 构造回复数据
char reply_data[512];
time_t now = time(NULL);
snprintf(reply_data, sizeof(reply_data),
"{\"status\": \"success\", \"message\": \"收到消息\", \"timestamp\": %lld}",
(long long)now);
// 发送事件回前端
char event_data_str[256];
snprintf(event_data_str, sizeof(event_data_str),
"{\"message\": \"处理完成\", \"original_data\": %s, \"timestamp\": %lld}",
event_data, (long long)now);
send_event(window_id, "backend-message", event_data_str);
// 返回结果给 invoke 调用 - 使用 jade_text_create 创建安全文本指针
return jade_text_create(reply_data);
}
// 页面加载完成处理回调
const char* page_loaded_callback(uint32_t window_id, const char* event_data) {
printf("页面加载完成,窗口 ID:%u\n", window_id);
// 发送欢迎事件
char welcome_msg[256];
time_t now = time(NULL);
snprintf(welcome_msg, sizeof(welcome_msg),
"{\"message\": \"欢迎使用 JadeView IPC 通信示例\", \"timestamp\": %lld}",
(long long)now);
send_event(window_id, "backend-message", welcome_msg);
// 返回确认结果 - 使用 jade_text_create 创建安全文本指针
return jade_text_create("{\"status\": \"success\", \"message\": \"页面加载确认\"}");
}
// app-ready 事件处理器
int app_ready_callback(int success, const char* reason) {
if (success == 1 && reason && strcmp(reason, "success") == 0) {
printf("JadeView 准备就绪\n");
// 注册消息处理器
// 注意:实际注册方式可能根据 API 变化而不同
// 这里仅展示概念
// 创建 WebView 窗口
WebViewWindowOptions options = {
.title = "IPC 通信示例",
.width = 800,
.height = 600,
.resizable = 1,
.remove_titlebar = 0
};
WebViewSettings settings = {
.autoplay = 0,
.background_throttling = 0,
.disable_right_click = 0,
.allow_fullscreen = 0,
.postmessage_whitelist = NULL
};
uint32_t window_id = create_webview_window(
"http://localhost:8080", // 本地服务器 URL
0,
&options,
&settings
);
if (window_id == 0) {
printf("窗口创建失败\n");
}
}
return 0;
}
int main() {
// 初始化 DLL
int result = JadeView_init(1, NULL, NULL);
if (result == 0) {
printf("DLL 初始化失败\n");
return 1;
}
// 注册 app-ready 事件
// 注意:实际注册方式可能根据 API 变化而不同
// 这里仅展示概念
// 运行消息循环
run_message_loop();
// 清理资源
cleanup_all_windows();
return 0;
}
IPC 通信的最佳实践
1. 命令和事件命名规范
- 使用清晰、描述性的命令和事件名称
- 采用小写字母和连字符分隔(kebab-case)
- 避免使用过于通用的名称
- 为不同模块使用前缀,如
user-、system-、ui- - 命令和事件名称保持一致,便于前后端理解
2. 数据结构设计
- 保持请求和响应数据结构简单清晰
- 使用一致的数据格式
- 包含必要的元数据(如 timestamp)
- 为复杂数据提供清晰的类型定义
- 错误响应使用统一的格式,包含 code 和 message 字段
3. 错误处理
- 前端使用 try/catch 捕获 API 调用错误
- 后端向前端返回明确的错误代码和消息
- 记录详细的错误日志
- 避免崩溃,确保系统稳定性
4. 性能优化
- 避免频繁调用 API,合并相关请求
- 对大数据进行分页或压缩
- 合理使用事件推送,避免不必要的轮询
- 及时取消不再需要的事件订阅
- 保持 payload 简洁,只传递必要的数据
5. 安全性考虑
- 验证所有输入数据,防止恶意请求
- 对敏感数据进行加密传输
- 限制 API 调用频率,防止滥用
- 严格的本地通信限制,防止外部访问
- 只允许通过 local-server-api 创建的服务器页面使用通信 API
IPC 通信的高级特性
1. 支持的通信模式
JadeView 支持多种通信模式:
- 请求-响应模式:通过
jade.invoke()发送请求并等待响应 - 事件推送模式:通过
jade.on()监听后端事件 - 广播事件:发送给所有窗口的事件
- 定向事件:发送给特定窗口的事件
2. 事件优先级
JadeView 支持事件优先级:
- 高优先级:系统事件、紧急通知
- 中优先级:用户交互、数据更新
- 低优先级:日志、统计数据
3. 异步处理机制
JadeView 提供了完善的异步处理机制:
- 基于 Promise/async-await 设计,避免 UI 阻塞
- 自动处理异步请求的生命周期
- 支持请求超时机制
- 高效的事件分发系统
与其他框架的 IPC 通信对比
| 框架 | IPC 通信机制 | 性能 | 安全性 | 易用性 |
|---|---|---|---|---|
| JadeView | 基于自定义协议的 JSON 通信 | 高 | 高 | 简单易用 |
| Electron | IPC 模块 | 中 | 中 | 中等复杂度 |
| NW.js | WebSocket + IPC | 中 | 中 | 较复杂 |
| CEF | 自定义消息传递 | 高 | 中 | 复杂 |
总结
JadeView 的前后端双向 IPC 通信机制提供了高效、安全、易用的跨语言通信解决方案。通过简单的 API,开发者可以轻松实现前后端之间的数据交换和事件驱动开发。
- 高效:基于自定义协议的设计,确保低延迟(
<1ms往返)和高吞吐量 - 安全:严格的本地通信限制和验证机制
- 易用:基于 Web 标准的 API 设计,降低开发复杂度
- 灵活:支持请求-响应和事件驱动两种通信模式
- 资源高效:相比传统 IPC 方案,CPU 消耗降低 30%-50%,内存占用降低 20%-40%
JadeView 的 IPC 通信机制是构建现代化桌面应用的重要基础,为开发者提供了强大的前后端协作能力。通过 jade.invoke() 和 jade.on() 这两个简单的 API,开发者可以轻松实现前后端之间的高效通信,构建出高性能、响应迅速的桌面应用。