Electron 应用如何和其他应用通信
不知道大家在开发 electron 应用时,是否遇到过这样的需求:目前,公司有两个桌面应用,希望在启动一个应用时,尝试询问另一个应用的登录信息,实现自动登录。
类似这样的功能,我们如何实现?
习惯了 web 开发的同学可能立马就能想到,让应用启动一个本地 web 服务,通过 http 协议来通信,这是一个不错的方法。当然,今天我要讲的肯定不是这么简单。我要给大家讲的是如何通过 NamedPipe(命名管道) 和 Unix domain socket 来进行进程间通信, 这两种都是双工通信,前者是windows 的,后者是类 unix 上的。由于 Node 基于 libv 实现了跨平台,抹平了两个平台实现的差异,所以我们用 node 来实现就简单了许多。
Node: Net 模块
想要进行进程间通信,两个应用必然要有一个当担服务端(App.A),一个担当客户端(App.B)的角色。这里,我们借助 Node 的 Net 模块就可以实现进程间通信。
创建服务
const os = require("os");
const net = require("net");
const path = require("path")
const server = net.createServer((c) => {
// ...
});
// named pipe
sever.listen("\\\\.\\pipe\\App.A")
// unix socket, 以 mac 为例
server.listen(path.join(os.homedir(), 'Library/GroupContainer/.App.A.d/node.sock'))
// tcp/ip port
server.listen(10086);
连接服务
const net = require("net");
// 以 named pipe 为例
const handle = net.connect("\\\\.\\pipe\\App.A")
handle.on("error", () => {
// 连接失败
});
handle.on("ready", () => {
// 连接成功,后续可以使用 handle 句柄向通道内发送数据
});
handle.on("close", () => {
// 连接断开
})
创建 api,响应请求
const net = require("net")
net.createServer(socket => {
socket.on("error", (e) => {
// connect error
})
// client connected
socket.on("data", (buffer) => {
const command = buffer[0];
const dataLength = buffer.readUInt32LE(1); // 4 bytes
const dataStart = 5; // 1 byte + 4 bytes
const dataEnd = dataStart + dataLength;
const dataBuffer = buffer.slice(dataStart, dataEnd);
if (dataBuffer.byteLength !== dataLength) {
throw new Error("invalid data")
}
const json = dataBuffer.toString("utf-8"); // json
const data = JSON.parse(json)
// 处理请求数据 data
switch(command){
case 1: // get user login info
// ....
socket.write('xxxxx\n') // 写入数据
socket.end() // 发送数据
break;
case 2: // 其他 api 实现
default:
break;
}
})
})
上面的例子中可以看到,我对接受的数据做了一些格式上的约定,第1个字节表示 commandType, 第2-5 占用4个字节的 int32 数值用来表示后续数据实体的字节长度,简单校验数据的合法性,并截取需要的数据。这是使用 Buffer 传输数据的常用技巧,大家可以留意一下。
“客户端”如何请求“服务端”
const net = require("net");
const path = require("path");
const os = require("os");
const address = path.join(
os.homedir(),
"Library/Group Containers/.App.A.d/node.sock"
);
const handle = net.connect(address);
handle.on("error", (e) => {
// connect error
console.log(e);
});
handle.on("ready", () => {
//
const command = Buffer.from([1]);
const data = {
name: "张三",
};
const json = JSON.stringify(data);
const dataBuffer = Buffer.from(json, "utf-8");
const dataLength = dataBuffer.byteLength;
const dataLengthBuffer = Buffer.alloc(4);
dataLengthBuffer.writeUInt32LE(dataLength, 0);
const buffer = Buffer.concat([command, dataLengthBuffer, dataBuffer]);
handle.once("data", (data) => {
console.log("response =>>>", data); // 接收到应用A返回的数据
handle.destroy();
});
handle.write(buffer);
handle.end();
});
这样一个简单的进程间通信就完成了。
这个 demo 我会补充完整后放到 github 上供大家参考。
相关资料
转载自:https://juejin.cn/post/7094895531268243470