最近兜兜转转,看了各种各样的OPC UA的库,尤其是看了OPC Foundation的库后,特别困惑,直到耐着性子看完milo库的Server例子后,对于如何写一个OPC UA服务器终于有了一定的了解。
Milo是Eclipse开源的项目之一,GitHub地址:
Milo
我们直接通过Server的例程来了解整个Server是怎么运行的:
1.主体函数
public static void main(String[] args) throws Exception {
ExampleServer server = new ExampleServer();
server.startup().get();
final CompletableFuture<Void> future = new CompletableFuture<>();
Runtime.getRuntime().addShutdownHook(new Thread(() -> future.complete(null)));
future.get();
}
这是Server主体的main函数,主要包含了以下几点:
- 生成一个Server对象,并且启动Server
- 定义异步写的方式(CompletableFuture库还没怎么看)
2.Server的定义方式
接下来我们主要是看如何去定义一个Server
获取证书
SelfSignedHttpsCertificateBuilder httpsCertificateBuilder = new SelfSignedHttpsCertificateBuilder(httpsKeyPair);
httpsCertificateBuilder.setCommonName(HostnameUtil.getHostname());
HostnameUtil.getHostnames("0.0.0.0").forEach(httpsCertificateBuilder::addDnsName);
X509Certificate httpsCertificate = httpsCertificateBuilder.build();
这里是通过X509的方式去生成OPC UA所需要的证书文件,进行加密传输,具体可以看
生成证书
。
之后则是证书的验证相关。
OPC UA Server配置
String applicationUri = CertificateUtil
.getSanUri(certificate)
.orElseThrow(() -> new UaRuntimeException(
StatusCodes.Bad_ConfigurationError,
"certificate is missing the application URI"));
Set<EndpointConfiguration> endpointConfigurations = createEndpointConfigurations(certificate);
先获取证书中的uri地址,通过方法实现对端点的配置,配置方法详见milo ExampleServer
OpcUaServerConfig serverConfig = OpcUaServerConfig.builder()
.setApplicationUri(applicationUri)
.setApplicationName(LocalizedText.english("Eclipse Milo OPC UA Example Server"))
.setEndpoints(endpointConfigurations)
.setBuildInfo(
new BuildInfo(
"urn:eclipse:milo:example-server",
"eclipse",
"eclipse milo example server",
OpcUaServer.SDK_VERSION,
"", DateTime.now()))
//设置对应的证书管理器
.setCertificateManager(certificateManager)
//获取信任列表 --- 用于信任Application
.setTrustListManager(trustListManager)
.setCertificateValidator(certificateValidator)
// 这个还不太明白
.setHttpsKeyPair(httpsKeyPair)
.setHttpsCertificate(httpsCertificate)
//验证身份
.setIdentityValidator(new CompositeValidator(identityValidator, x509IdentityValidator))
//s设定生成的服务器URI
.setProductUri("urn:eclipse:milo:example-server")
.build();
server = new OpcUaServer(serverConfig);
配置OPCUA Server,具体信息已在代码中阐述,最后将其赋值给server,其中serrver在Example类中定义
private final OpcUaServer server;
3.配置Server的命名空间 – 即Server的属性
具体配置方式定义在ExampleServerfang方法中。
- 最前面的一大坨是后面例子中需要用的东西
super.onStartup()
这个是使用父类中的启动方法,用于生成服务器自身的节点信息
// Create a "HelloWorld" folder and add it to the node manager
NodeId folderNodeId = newNodeId("HelloWorld");
UaFolderNode folderNode = new UaFolderNode(
getNodeContext(),
folderNodeId,
newQualifiedName("HelloWorld"),
LocalizedText.english("HelloWorld")
);
getNodeManager().addNode(folderNode);
// Make sure our new folder shows up under the server's Objects folder.
folderNode.addReference(new Reference(
//产生引用的结点ID
folderNode.getNodeId(),
//引用的类型
Identifiers.Organizes,
//引用连接的对象
Identifiers.ObjectsFolder.expanded(),
//Reference的指向
false
));
生成根目录文件,并且天界一个对ObjectsFolder的引用,表示这是生成的一个对象,直属于Object。
注意这里的false代表的是reference的指向,true为正向,false为反向。
这里是给folderNode添加的引用,是对Object的,因此结果应该是:
Object -> folderNode 为true的话则是:folderNode->Object