node-red读取并修改IOT2000系列盒子网络参数节点
一、功能简述
- 此节点通过与SIMATIC IOT2000系列(包括IOT2040,IOT2050)工业物联网智能网关中服务器的数据交互,完成对工业物联网智能网关(以下均简称为盒子)网络参数的读取与修改;
- 用户界面中可选择不同网卡以修改或读取相应的网络参数;
- 网络参数输入框及服务端中加容错处理,若输入不符合网络参数格式(x.x.x.x)无法完成修改。
二、实现方式
- 首先在盒子中搭建服务器,通过监听客户端的
GET
或POST
请求,判断相对应的请求方法,通过child_process
模块直接执行系统命令的方法,以获取或修改盒子中的网络参数; - 运用正则获取interfaces文件中的网络参数,通过执行脚本文件修改网络参数;
- node-red节点中的HTML文件通过
GET
方式从服务端获取各网络参数,通过POST
方式将修改后的网络参数传送给服务端; - 在用户端界面和服务端修改参数前添加容错处理,防止由于用户的误操作改为错误的网络参数。
三、服务端
1.搭建简易服务器
首先通过nodejs中的http模块,搭建出盒子中简易的服务器,通过监听事件可以进行客户端和服务端间的数据交互。
// http模块为nodejs内置模块不需要安装,仅需require即可
let http = require("http");
// 创建server服务器对象。
let server = http.createServer();
// 监听对当前服务器对象的请求。当服务器被请求时,会触发请求事件,并传入请求对象返回响应对象
server.on('request', function (req, res) {
// 功能函数模块,此处示例返回response字符串
res.end('response')
});
// 启动侦听连接的HTTP服务器,启动服务
server.listen(3000, function () {
console.log("Server started successfully")
});
2.URL
概念:在WWW上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位器),它是WWW的统一资源定位标志,就是指网络地址。
语法:URL由三部分组成:资源类型、存放资源的主机域名、资源文件名。也可认为由4部分组成:协议、主机、端口、路径。
格式:(带方括号[ ]的为可选项)
protocol : // hostname[:port] / path / [;parameters][?query]#fragment
- protocol(协议)
指定使用的传输协议,下表列出 protocol 属性的有效方案名称。 最常用的是HTTP协议,它也是WWW中应用最广的协议。 - hostname(主机名)
是指存放资源的服务器的域名系统(DNS) 主机名或 IP 地址。有时,在主机名前也可以包含连接到服务器所需的用户名和密码(格式:username:password@hostname)。 - port(端口号)
整数,可选,省略时使用方案的默认端口,各种传输协议都有默认的端口号,如http的默认端口为80。如果输入时省略,则使用默认端口号。有时候出于安全或其他考虑,可以在服务器上对端口进行重定义,即采用非标准端口号,此时,URL中就不能省略端口号这一项。 - path(路径)
由零或多个“/”符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。 - parameters(参数)
这是用于指定特殊参数的可选项。 - query(查询)
可选,用于给动态网页(如使用CGI、ISAPI、PHP/JSP/ASP/ASP.NET等技术制作的网页)传递参数,可有多个参数,用“&”符号隔开,每个参数的名和值用“=”符号隔开。 - fragment(信息片断)
字符串,用于指定网络资源中的片断。例如一个网页中有多个名词解释,可使用fragment直接定位到某一名词解释。
注意:node.js中的url模块可用于解析和处理URL字符串,其提供了用于url分辨和解析的实用程序。URL字符串是包含多个有意义组件的结构化字符串。解析后,将返回一个URL对象,其中包含这些组件的属性。url模块提供了三个方法:parse,format,resolve。此处只选用parse方法:
// 创建url对象
const urlLib = require('url');
// url.parse()方法解析一个JSON字符串,构造由该字符串描述的JavaScript值或对象
var urlObj = urlLib.parse(req.url, true);
3.与客户端的数据交互
HTTP/1.1协议中共定义了八种方法(有时也叫“动作”),来表明Request-URL指定的资源不同的操作方式,分别是GET,POST,HEAD,OPTIONS, PUT,DELETE,TRACE和CONNECT方法。
此处数据交互只用到GET和POST两种方法,GET方法表示此次访问主要目的是请求数据,POST方法表示此次访问主要目的是提交数据并进行处理。
// method为解析器支持的HTTP方法列表。若客户端请求方法为GET,则执行以下程序
if (req.method === 'GET') {
console.log(urlObj);
// 若路径名为/getIpMsg,则执行以下程序
if (urlObj.pathname == "/getIpMsg") {
// 返回给客户端信息,并结束此次响应
res.end('GET');
}
}
// 若客户端请求方法为POST,则执行以下程序
else if (req.method === 'POST') {
console.log(urlObj);
// 将接受到的数据放在data中
let data = ''
req.on('data', function (chunk) {
data += chunk;
console.log(data);
});
req.on('end', function () {
console.log(data);
// 用JSON.parse方法解析data数据
data = JSON.parse(data);
console.log(data);
// 返回给客户端信息,并结束此次响应
res.end('POST');
})
}
// 若客户端请求方法为其他,则不执行并返回拒收信息
else {
res.end('Please re-select the request method')
}
4.网络参数的读取与修改
网络参数的读取与修改涉及到服务器对盒子内部系统命令的调用。在NodeJS中是利用子进程来调用系统命令或者文件的,NodeJS子进程提供了与系统交互的重要接口,此处用到提供直接执行系统命令的方法child_process.exec(cmd, [options], callback)
和提供调用脚本文件的方法child_process.execFile(file, [args], [options], [callback])
(1)GET请求
若客户端请求为GET,则服务器需要提取盒子中响应的网络参数进行处理并返回请求数据。
此处提取网络参数所用的方法为调用child_process.exec
命令对interfaces文件使用cat命令,再通过正则,分别将两个网卡上的ip,子网掩码,网关和DNS数据以json格式返回给客户端。
注意:通过从interfaces文件中筛选获取网络参数的方法存在一定弊端,需事先对interfaces文件进行配置,在不能保证网卡interfaces文件格式与上述程序适配的情况下,不适用于初次使用。
通常interfaces文件需要以如下格式进行配置:
# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8)
# The loopback interface
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.200.1
netmask 255.255.255.0
gatway 192.169.200.254
dns-nameservers 8.8.8.8
auto eth1
iface eth1 inet static
address 192.168.50.44
netmask 255.255.255.0
gatway 192.168.50.254
dns-nameservers 8.8.8.8
(2)POST请求
若客户端请求为POST,则服务器需要接受数据进行处理,并修改盒子中的网络参数。
此处修改网络参数所用的方法为先接收客户端传来的数据进行解析及容错处理,再调用child_process.execFile
命令执行修改网络参数的脚本文件ip1_shell.sh
和ip2_shell.sh
。
修改网络参数的脚本相关知识及运行原理在之前的文章中有提过,在此不再赘述。
注意:
-
调用脚本时请注意调整为相应的路径;
-
脚本在调用前需进行授权操作
chmod 777 /shell01/ip1_shell.sh
,否则会提示“没有权限”的错误提示。
-
与GET相同的,POST也需添加跨域处理。
四、客户端
此处的客户端即为node-red中的parameters节点,尤其特指parameters.html文件,主要功能皆由html文件实现。客户端绝大部分功能都在服务器开启的前提下才能实现,使用调试前需注意应先启动服务器。
1.功能说明
初次打开用户界面时,只能输入名字与服务器ip。在输入服务器ip后点击“获取服务端数据”按钮获取相关数据,同时显现出IP,Netmask,Gateway,DNS四个数据和选择网卡窗口。在选择网卡一栏中,可通过下拉菜单选择不同的网卡获取相应的网络参数。修改完成后,点击右上的红色按钮“完成”即可发送数据给服务端,进而由服务端完成修改网络参数的任务。
为防止由客户的错误操作造成盒子网络参数混乱或盒子网络设备运行状态异常,许多地方添加了限制和容错处理。在与服务端建立连接前隐藏各网络参数,防止连接服务器前出现显示数据紊乱的情况;通常将网卡1作为调试口(需事先向客户说明),将网卡1的所有网络参数数据锁死不许修改,否则修改后会立即与服务器断开连接,极容易因为输入错误或记不清造成无法重连的情况;在网络参数各输入框中加入正则校验防止因格式问题造成修改错误问题,若格式不符合网络参数格式会提示数据无效。
2.界面设计
在显示数据时计划采用显隐两种方式切换显示两个网卡接受到的数据,事先应安排好相应的输入框。
为实现界面要素显隐模式的切换以及方便其他要素在输入内容不同状态下(符合格式与不符合格式)进行不同模式的转换,采用类似状态机原理的状态切换模式来管理界面的变化和与服务器的通信方式。
在刚开始的时候,也就是实际应用中将节点拖至工作区,至输入服务器ip地址获取数据之前的时候,定义此时为初始态,不可输入信息,不可切换网卡,无校验信息,点击完成后没有任何操作。
在点击获取数据按钮之后,网络参数输入格式错误时,定义此时为异常态,此时开校验,显示“请输入正确数据”,可看到各项数据并切换网卡,点击完成不会发送数据。
在输入完成且校验正常,定义此时为完成态,点击“完成”按钮后向服务器发送数据。
3.XMLHttpRequest
AJAX即“Asynchronous Javascript And XML”(异步JavaScript 和XML),是指一种创建交互式网页应用的网页开发技术。而XMLHttpRequest
对象是AJAX功能的核心。使用XMLHttpRequest
(XHR)对象与服务器交互。您可以从URL检索数据,而不必刷新整个页面。这使得Web页面只更新页面的一部分,而不会干扰用户正在做的事情。XMLHttpRequest
在AJAX编程中大量使用。
方法:
open
() 说明:初始化 HTTP 请求参数,例如 URL 和 HTTP 方法,但是并不发送请求。abort
() 说明:取消当前响应,关闭连接并且结束任何未决的网络活动。getAllResponseHeaders
() 说明:把 HTTP 响应头部作为未解析的字符串返回。getResponseHeader
() 说明:返回指定的 HTTP 响应头部的值。send
() 说明:发送 HTTP 请求,使用传递给 open() 方法的参数,以及传递给该方法的可选请求体。setRequestHeader
() 说明:向一个打开但未发送的请求设置或添加一个 HTTP 请求。
属性:
readyState
说明:HTTP 请求的状态。responseText
说明:目前为止为服务器接收到的响应体(不包括头部),或者如果还没有接收到数据的话,就是空字符串。responseXML
说明:对请求的响应,解析为 XML 并作为 Document 对象返回。status
说明:由服务器返回的 HTTP 状态代码。statusText
说明:这个属性用名称而不是数字指定了请求的 HTTP 的状态代码。
需要注意的是XMLHttpRequestEventTarget
是描述可以在对象中实现的事件处理程序的接口,该对象将处理XMLHttpRequest
的事件。XMLHttpRequest
继承了其属性,因此onabort
,onerror
,onload
,ontimeout
等属性也是可以通用的。
若有兴趣了解Ajax或者想对XMLHttpRequest
进行深入了解的,请点击
XMLHttpRequest 和 Fetch API
4.与服务端的数据交互
此处使用XMLHttpRequest
(XHR)对象与服务器进行数据交互,接收数据后将各网络参数赋给相应的输入框,发送数据时提取输入框中的数据,经过处理后发送给服务器。
在构建编辑对话框时调用的oneditprepare
中接收并处理数据。
// 提取输入的服务器IP地址
var http = $('#node-input-postname').val();
console.log('访问服务端,获取IP信息');
// 构造函数初始化一个XMLHttpRequest。它必须在任何其他方法调用之前被调用。
let xhr = new XMLHttpRequest();
// 初始化新创建的请求
xhr.open('GET', 'http://' + http + ':3000/getIpMsg');
console.log('http://' + http + ':3000/getIpMsg');
// 当HTTP请求返回并且成功获取内容后,接收加载事件。
xhr.onload = e => {
// 此处填写相应功能模块
};
// 请求结束
xhr.onloadend = e => {
console.log('request loadend');
};
// 请求出错
xhr.onerror = e => {
console.log('request error');
};
// 请求超时
xhr.ontimeout = e => {
console.log('request timeout');
};
// 将请求发送到服务器
xhr.send(null);
在构建编辑对话框时调用的oneditsave
中发送数据。
五、功能实现
读取网络参数过程:
修改网络参数过程: