Electron底层通信与歧义分析(一)
导语
和其他应用层开发技术一样,electron并没有操作底层或者使用底层的api的能力,不过,electron内置了nodejs环境,nodejs是可以进行底层的交互的,这也是electron能进行底层通信的原理。对于通信模块,nodejs支持大多数通信协议,这些协议从应用层到链路层都有分布,值得注意的是nodejs是一个JavaScript运行时环境,本身不支持包括数据链路层以下的通信协议,比如以太网协议和PPP协议等,但是可以通过第三方包(npm-arp等)来支持ARP等数据链路层协议。
第三方包链路层协议实现理解分歧解释
此处需需要区分的是,诸如npm-arp等部分第三方包,实现数据链路层协议的方式并不是进行底层编程,不能单纯理解第三方包能实现协议而理解脱离了nodejs环境自身能够做到底层编程,并且要知道的是,数据链路层的网络编程依靠的是硬件环境与系统环境本身,例如,如果一台单片机上并没有网络接口,或者某些特殊系统上没有对arp等协议的实现,那么这些第三包是不可用的,原因是因为在OIS模型中,数据链路层已经是数据解析层面了,数据解析还是需要依靠硬件的支持。所以,**第三方包实现数据链路层协议的方式不是通过底层编程或者自实现,而是通过nodejs提供的命令行功能(spawn方法)来实现的**,也就是说,在这些包的底层,你可以看到它们的源码是这样的
var spawn = require('child_process').spawn;
/**
* read from arp -n IPADDRESS
*/
module.exports.readMACLinux = function(ipaddress, cb) {
// ping the ip address to encourage the kernel to populate the arp tables
var ping = spawn("ping", [ "-c", "1", ipaddress ]);
ping.on('close', function (code) {
// not bothered if ping did not work
var arp = spawn("arp", [ "-n", ipaddress ]);
var buffer = '';
var errstream = '';
arp.stdout.on('data', function (data) {
buffer += data;
});
arp.stderr.on('data', function (data) {
errstream += data;
});
arp.on('close', function (code) {
if (code !== 0) {
console.log("Error running arp " + code + " " + errstream);
cb(true, code);
return;
}
//Parse this format
//Lookup succeeded : Address HWtype HWaddress Flags Mask Iface
// IPADDRESS ether MACADDRESS C IFACE
//Lookup failed : HOST (IPADDRESS) -- no entry
//There is minimum two lines when lookup is successful
var table = buffer.split('\n');
if (table.length >= 2) {
var parts = table[1].split(' ').filter(String);
cb(false, parts.length == 5 ? parts[2] : parts[1]);
return;
}
cb(true, "Could not find ip in arp table: " + ipaddress);
});
});
};
依照npm-arp这个arp协议的实现举例来说,以上实例代码是Mac环境下获取系统物理地址的实现,示例中通过创建一个nodejs子进程来调用spawn方法执行ping命令查询传入的ip地址是否存在设备
ping -c 1 ip
其后又通过同样的方式执行arp命令转换将ip地址为物理地址,从而获取占用传入ip的设备的物理地址
arp -n ip
所以,底层还是要看系统是否支持arp协议。
使用MAC地址交互
首先,electron是不能直接获取MAC地址并与局域网内其他设备进行交互,但是可以使用npm-arp插件通过局域网内设备的ip地址解析出MAC地址,再通过nodejs本身自带的dgram模块来进行UDP协议交互或者net模块来进行TCP交互,但是需要注意的时,此处使用的MAC地址通信并不是数据链路层那样的直接通过MAC地址收发数据包,而UDP协议本身也不是通过MAC地址来收发数据,此处使用MAC地址,只是在IP地址和端口的基础上**加上**MAC地址通信,它的作用是绕过路由器的转发阶段,直接发送到目标设备,提高数据包传输速率
net模块和dgram模块
在nodejs中,提供了**net模块和dgram模块**来对OSI七层模型、TCP/IP四层模型这类计算机网络体系结构的标准化框架中传输层协议进行实现。并且nodejs底层通信中,传输层也是底层通信实现的重点,但不意味nodejs不能再深入底层实现其他层面的通信,nodejs之所以将传输层作基础通信的最底端实现,是因为应用层开发中,是不需要关心底层数据帧、寻址等功能的实现,应用层的http、https、webSocket等协议其实已经包含了该部分,nodejs是关注应用层开发的框架,无需冗余实现更底层的通信,不过由于nodejs的扩展能力非常好,开发者依旧能通过c++插件等方式实现更底层的通信协议
net模块是对TCP协议通信的实现
const net = require('net');
// 创建一个TCP连接
const client = new net.Socket();
// 连接到目标服务器
const targetHost = '目标服务器IP地址';
const targetPort = 8080;
client.connect(targetPort, targetHost, () => {
console.log('已连接到服务器');
// 发送数据
const message = 'Hello, TCP Server!';
client.write(message);
// 关闭连接
client.end();
});
// 监听数据接收事件
client.on('data', (data) => {
console.log('收到服务器回复:', data.toString());
});
// 监听连接关闭事件
client.on('close', () => {
console.log('连接已关闭');
});
// 监听连接错误事件
client.on('error', (error) => {
console.error('连接发生错误:', error.message);
});
dgram模块是对UDP协议通信的实现
const dgram = require('dgram');
// 创建一个UDP套接字
const client = dgram.createSocket('udp4');
// 要发送的数据
const message = 'Hello, UDP Server!';
// 目标服务器的IP地址和端口号
const targetHost = '目标服务器IP地址';
const targetPort = 8080;
// 发送数据
client.send(message, targetPort, targetHost, (error) => {
if (error) {
console.error('发送数据失败:', error);
} else {
console.log('数据发送成功!');
}
// 关闭套接字
client.close();
});
评论区