日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

OPCUA标准java实现 Milo库

發(fā)布時(shí)間:2023/12/14 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OPCUA标准java实现 Milo库 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Milo庫(kù)

今天跟大家來(lái)介紹一下一個(gè)OPC UA協(xié)議的開(kāi)源庫(kù),我們使用的現(xiàn)場(chǎng)設(shè)備為西門(mén)子的S7-1500 CPU,西門(mén)子的S7-1500在V2.1版本后就直接可以作為OPC UA的服務(wù)器來(lái)供其他客戶端訪問(wèn)。所以用OPC協(xié)議來(lái)進(jìn)行數(shù)據(jù)采集就是最好的方式。

計(jì)算機(jī)語(yǔ)言采用java,所以也花了很大的力氣來(lái)找OPC UA通信協(xié)議的java實(shí)現(xiàn)庫(kù),盡管OPC Foundation在Github上也有協(xié)議的java實(shí)現(xiàn),但是各種學(xué)習(xí)的資源很有限,學(xué)習(xí)曲線比較陡峭。然后碰巧在Github上找到了一個(gè)OPC UA的開(kāi)源庫(kù),就是今天要介紹的 Milo,據(jù)了解該項(xiàng)目的Eclipse旗下的一個(gè)物聯(lián)網(wǎng)的項(xiàng)目,是一個(gè)高性能的OPC UA棧,提供了一組客戶端和服務(wù)端的API,支持對(duì)實(shí)時(shí)數(shù)據(jù)的訪問(wèn),監(jiān)控,報(bào)警,訂閱數(shù)據(jù),支持事件,歷史數(shù)據(jù)訪問(wèn),和數(shù)據(jù)建模。

Milo Github鏈接

Milo 初探

在Milo中大量的采用了java 8的新特性CompletableFuture來(lái)進(jìn)行異步操作,Milo中有大量的操作都是直接返回CompletableFuture對(duì)象,還有大量使用函數(shù)接口和接口默認(rèn)方法等新特性,所以JDK的版本要8.0,對(duì)CompletableFuture不太熟悉的可以先去了解CompletableFuture的相關(guān)概念在來(lái)看Milo的官方例子會(huì)輕松很多。

添加依賴


好了,下面就添加相關(guān)依賴,Milo的依賴有三個(gè)Stack,Client SDK,Server SDK。

Client SDK依賴

<dependency><groupId>org.eclipse.milo</groupId><artifactId>sdk-client</artifactId><version>0.2.4</version> </dependency>

Server SDK依賴

<dependency><groupId>org.eclipse.milo</groupId><artifactId>sdk-server</artifactId><version>0.2.4</version> </dependency>

Stack依賴

<dependency><groupId>org.eclipse.milo</groupId><artifactId>stack-client</artifactId><version>0.2.4</version> </dependency><dependency><groupId>org.eclipse.milo</groupId><artifactId>stack-server</artifactId><version>0.2.4</version> </dependency>

目前最新的版本是0.2.4

開(kāi)發(fā)客戶端就添加客戶端的依賴,開(kāi)發(fā)服務(wù)端就添加服務(wù)端的依賴。一般來(lái)說(shuō)Stack依賴并不需要手動(dòng)添加,在我們添加Client SDK或者Server SDK的時(shí)候會(huì)包含了Stack依賴。

添加bouncycastle依賴


為什么需要添加bouncycastle依賴?因?yàn)閯?chuàng)建OPC UA客戶端必須要有相關(guān)的數(shù)字證書(shū),而bouncycastle就作為解析相關(guān)的數(shù)字證書(shū)的庫(kù)所以要添加相關(guān)的bouncycastle依賴。

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk15on</artifactId><version>1.57</version> </dependency>

所以如果我們開(kāi)發(fā)OPC UA客戶端,總的依賴項(xiàng)也很簡(jiǎn)單,如下:

<dependency><groupId>org.eclipse.milo</groupId><artifactId>sdk-client</artifactId><version>0.2.4</version> </dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk15on</artifactId><version>1.57</version> </dependency>

搜索服務(wù)節(jié)點(diǎn)


首先要?jiǎng)?chuàng)建OPC客戶端第一件事當(dāng)然是指定一個(gè)URL。以S7-1500的CPU為例,可以在博圖軟件的組態(tài)界面雙擊CPU然后再屬性窗口里面找到OPC選項(xiàng)卡然后里面就會(huì)有這個(gè)CPU的OPC UA的URL。拿到這個(gè)URL后就可以在java中定義這個(gè)地址。

//在西門(mén)子S7-1500中OPC UA服務(wù)器的端口默認(rèn)為4840 String EndPointUrl = "opc.tcp://localhost:4840";

獲取服務(wù)節(jié)點(diǎn)列表

對(duì)應(yīng)的OPC UA服務(wù)地址(也就是上面定義的字符串)的節(jié)點(diǎn)并不止一個(gè),因?yàn)樵谝粋€(gè)對(duì)應(yīng)的OPC UA服務(wù)地址里面可能也有不一樣的服務(wù)器安全策略,每種不同安全策略對(duì)應(yīng)一個(gè)節(jié)點(diǎn)。以S7-1500為例就有下面幾種安全策略。

  • 無(wú)安全設(shè)置
  • Basic128Rsa15 - 簽名
  • Basic128Rsa15 - 簽名和加密
  • Basic256 - 簽名
  • Basic256 - 簽名和加密
  • Basic256Sha256 - 簽名
  • Basic256Sha256 - 簽名和加密

以上策略可以在S7-1500 CPU的組態(tài)中選擇啟用哪一個(gè)。然后在java中就會(huì)搜索到相應(yīng)的節(jié)點(diǎn)。

EndpointDescription[] endpointDescription = UaTcpStackClient.getEndpoints(EndPointUrl).get();//過(guò)濾掉不需要的安全策略,選擇一個(gè)自己需要的安全策略EndpointDescription endpoint = Arrays.stream(endpoints).filter(e -> e.getSecurityPolicyUri().equals(securityPolicy.getSecurityPolicyUri())).findFirst().orElseThrow(() -> new Exception("no desired endpoints returned"));

接下來(lái)創(chuàng)建配置類,然后再用這個(gè)配置類來(lái)生成OPC客戶端對(duì)象。

OpcUaClientConfig config = OpcUaClientConfig.builder().setApplicationName(LocalizedText.english("OPCAPP")).setApplicationUri("urn:LAPTOP-AQ90KJVR:OPCAPP").setCertificate(certificate).setKeyPair(keyPair).setEndpoint(endpoint).setIdentityProvider(new UsernameProvider("username","password")).setRequestTimeout(uint(5000)).build();OpcUaClient opcClient = new OpcUaClient(config);

下面就來(lái)對(duì)上面這些代碼左一個(gè)解釋。

在我們調(diào)用了builder后就要進(jìn)行一些基本的客戶端設(shè)置,setCertificate()有一個(gè)X509Certificate對(duì)象的形參,表示設(shè)置的數(shù)字證書(shū)(OPCUA應(yīng)用都需要有數(shù)字證書(shū)和密匙對(duì)來(lái)創(chuàng)建,而數(shù)字證書(shū)和密匙對(duì)我們可以自己創(chuàng)建,具體的生成數(shù)字證書(shū)的方法這里就不討論了,具體的可以到我博客的另一篇文章中看到或者到我的Github上有相關(guān)例程)。
OPCUA標(biāo)準(zhǔn)java實(shí)現(xiàn) Milo庫(kù) 證書(shū)的生成和使用
GitHub關(guān)于Milo庫(kù)使用證書(shū)例程

setKeyPair()接受一個(gè)KeyPair對(duì)象表示密匙對(duì)。

setEndpoint()接受一個(gè)EndpointDescription對(duì)象,就是設(shè)置剛剛我們選擇的節(jié)點(diǎn)就可以了。

setIdentityProvider()該方法表示指定客戶端使用的訪問(wèn)驗(yàn)證方式,接受一個(gè)IdentityProvider接口,而Milo庫(kù)為我們提供了4個(gè)IdentityProvider接口的實(shí)現(xiàn)。

  • AnonymousProvider
  • CompositeProvider
  • UsernameProvider
  • X509IdentityProvider

我自己比較常用第一個(gè)匿名驗(yàn)證和第三個(gè)用戶名驗(yàn)證方式,因?yàn)檫@兩種驗(yàn)證方式也方便簡(jiǎn)單。

上面的例子中使用的是用戶名和密碼驗(yàn)證方式,對(duì)于該驗(yàn)證方式只需要實(shí)例化一個(gè)UsernameProvider類,在構(gòu)造函數(shù)中設(shè)置用戶名和密碼。
這樣在創(chuàng)建和OPC UA服務(wù)器連接的時(shí)候會(huì)與服務(wù)器中設(shè)置的授權(quán)的用戶名和密碼比對(duì),符合的話就允許連接。

對(duì)于AnonymousProvider匿名驗(yàn)證方式就更簡(jiǎn)單了,只需要實(shí)例化一個(gè)AnonymousProvider對(duì)象不需要輸入任何的實(shí)參。匿名連接到OPC UA服務(wù)器。

setRequestTimeout()設(shè)置請(qǐng)求超時(shí)時(shí)間,單位為毫秒。

最后通過(guò)該config對(duì)象最終創(chuàng)建OPCUA的客戶端對(duì)象OpcUaClient opcClient = new OpcUaClient(config);
在有了這個(gè)OpcUaClient對(duì)象后我們就能夠開(kāi)始訪問(wèn)OPC UA服務(wù)器來(lái)進(jìn)行現(xiàn)場(chǎng)的信息采集了。

瀏覽節(jié)點(diǎn),讀,寫(xiě)

瀏覽節(jié)點(diǎn)


在OPC UA中的讀和寫(xiě)是對(duì)OPC地址空間中的節(jié)點(diǎn)進(jìn)行訪問(wèn),地址空間中的節(jié)點(diǎn)都實(shí)現(xiàn)了Node接口,由于其實(shí)現(xiàn)類太多了
這里就不一一羅列出來(lái)了。

下面我們就來(lái)瀏覽一個(gè)節(jié)點(diǎn):

public void browseNode(OpcUaClient client){//開(kāi)啟連接client.connect().get();List<Node> nodes = client.getAddressSpace.browse(Identifiers.RootFolder).get();for(Node node:nodes){System.out.println("Node= " + node.getBrowseName().get().getName());} }

正如上面所見(jiàn)我們只需要不到幾行的代碼就完成了節(jié)點(diǎn)的瀏覽訪問(wèn),從上面的方法可以看到形參是一個(gè)OpcUaClient對(duì)象
而該對(duì)象我們?cè)谏弦还?jié)已經(jīng)創(chuàng)建了,我們對(duì)傳入的OpcUaClient對(duì)象調(diào)用getAddressSpace()來(lái)獲取地址空間對(duì)象,AddressSpace對(duì)象
有很多用于訪問(wèn)節(jié)點(diǎn)的方法,這里我們調(diào)用browse()方法,該方法接受一個(gè)NodeId對(duì)象來(lái)表示開(kāi)始瀏覽的根節(jié)點(diǎn),隨后方法會(huì)
瀏覽根節(jié)點(diǎn)下的所有節(jié)點(diǎn),并返回一個(gè)CompletableFuture<List<Node>>對(duì)象(此處用到了java8.0的新特性)。
在browse()后調(diào)用get()以阻塞的方式等待返回。

在上面例子中的Identifiers.RootFolder是Milo庫(kù)預(yù)定義的根目錄,Identifiers中還有很多其他的預(yù)定于NodeId,當(dāng)然我們也可以
自己new一個(gè)NodeId出來(lái),這都是可以的。

隨后對(duì)我們獲取到的節(jié)點(diǎn)列表進(jìn)行歷遍并且打印每一個(gè)節(jié)點(diǎn)的名稱到標(biāo)準(zhǔn)輸出。

以上就是對(duì)OPC UA地址空間中的節(jié)點(diǎn)進(jìn)行訪問(wèn)的過(guò)程,相當(dāng)?shù)暮?jiǎn)單。

獲取節(jié)點(diǎn)值


獲取節(jié)點(diǎn)的值也是一樣的簡(jiǎn)單,廢話不多說(shuō)直接上代碼。

public void readValue(OpcUaClient client){//創(chuàng)建連接client.connect().get();NodeId nodeId = new NodeId(3,"\"test_value\"");DataValue value = client.readValue(0.0, TimestampsToReturn.Both, nodeId).get();System.out.println((Integer)value.getValue().getValue()); }

以上的代碼從PLC中讀取了名為"test_value"的變量,并且把值打印在了標(biāo)準(zhǔn)輸出中。

下面我們來(lái)看下上面的代碼是怎么回事,首先我們創(chuàng)建了連接,由于Milo庫(kù)大量采用了CompletableFuture,所以大家會(huì)在很多地方看到
調(diào)用get()方法來(lái)阻塞等待方法返回。然后是創(chuàng)建了一個(gè)NodeId對(duì)象,該對(duì)象的構(gòu)造函數(shù)共有10個(gè)重載,我個(gè)人比較經(jīng)常用到的是:

/*** @param namespaceIndex the index for a namespace URI. An index of 0 is used for OPC UA defined NodeIds.* @param identifier the identifier for a node in the address space of an OPC UA Server.*/ public NodeId(int namespaceIndex, String identifier) {//... }

以S7-1500 PLC為例,所有的變量的地址空間的索引都是整數(shù)3,標(biāo)識(shí)就是PLC中的變量名(注意要帶雙引號(hào))。
創(chuàng)建好NodeId后就可以讀取變量的值了。

調(diào)用OpcUaClient對(duì)象的readValue()方法讀取變量值,該方法接受三個(gè)參數(shù)

default CompletableFuture<DataValue> readValue(double maxAge,TimestampsToReturn timestampsToReturn,NodeId nodeId) {//... }

第一個(gè)參數(shù)如果設(shè)置為0的話會(huì)獲取最新的值,如果maxAge設(shè)置到Int32的最大值,則嘗試從緩存中讀取值。
第二個(gè)參數(shù)為請(qǐng)求返回的時(shí)間戳,第三個(gè)參數(shù)為要讀取的NodeId對(duì)象。

該對(duì)象也是返回的CompletableFuture<DataValue>,這里可以發(fā)現(xiàn)它返回的是一個(gè)DataValue對(duì)象,在該對(duì)象中有一個(gè)Variant
對(duì)象來(lái)存放真正的值,為了獲取PLC變量的值,我們需要從readValue()中返回的DataValue中調(diào)用.getValue()來(lái)獲取
其中的Variant對(duì)象,然后再次調(diào)用getValue()方法來(lái)獲得真正的值。Variant中的值的類型是Object,所以獲取到值后需要強(qiáng)制轉(zhuǎn)換到我們所需要的值然后再使用。

以上就是讀取PLC中的變量值的代碼了,也是很簡(jiǎn)單的對(duì)吧。

寫(xiě)變量


下面來(lái)展示對(duì)變量寫(xiě)入值,代碼如下:

public void writeValue(OpcUaClient client, int value){//創(chuàng)建連接client.connect().get();//創(chuàng)建變量節(jié)點(diǎn)NodeId nodeId = new NodeId(3,"\"test_value\"");//創(chuàng)建Variant對(duì)象和DataValue對(duì)象Variant v = new Variant(value);DataValue dataValue = new DataValue(v,null,null);StatusCode statusCode = client.writeValue(nodeId,dataValue).get();System.out.println(statusCode.isGood()); }

向PLC變量寫(xiě)入值的代碼跟讀取的代碼差不多,不同的是需要?jiǎng)?chuàng)建一個(gè)Variant然后再用這個(gè)Variant對(duì)象創(chuàng)建DataValue對(duì)象。
OpcUaClient對(duì)象的writeValue()的方法接受一個(gè)需要寫(xiě)入的變量節(jié)點(diǎn),和一個(gè)值對(duì)象DataValue,該方法返回的是一個(gè)StatusCode對(duì)象
,上面的代碼把返回來(lái)的StutusCode判斷是否為Good,并且輸出到標(biāo)準(zhǔn)輸出中來(lái)。

以上就是向PLC變量寫(xiě)入值的代碼,Milo庫(kù)為我們封裝了大量的操作,使得在對(duì)變量的讀寫(xiě)甚至之后介紹到的操作中都更便利了。

訂閱變量

對(duì)于讀取PLC里面的變量,有時(shí)候我們更需要的是當(dāng)變量變化的時(shí)候客戶端能夠收到并且做出相應(yīng)的反應(yīng),而不是對(duì)變量作輪詢讀取。OPC UA提供了創(chuàng)建變量監(jiān)控和訂閱的方式來(lái)監(jiān)控對(duì)應(yīng)變量的變化。

public void createSubscription(OpcUaClient client){//創(chuàng)建連接client.connect().get();//創(chuàng)建發(fā)布間隔1000ms的訂閱對(duì)象UaSubscription subscription = client.getSubscriptionManager().createSubscription(1000.0).get();//創(chuàng)建訂閱的變量NodeId nodeId = new NodeId(3,"\"test_value\"");ReadValueId readValueId = new ReadValueId(nodeId,AttributeId.Value.uid(),null,null);//創(chuàng)建監(jiān)控的參數(shù)MonitoringParameters parameters = new MonitoringParameters(uint(1),1000.0, // sampling intervalnull, // filter, null means use defaultuint(10), // queue sizetrue // discard oldest);//創(chuàng)建監(jiān)控項(xiàng)請(qǐng)求//該請(qǐng)求最后用于創(chuàng)建訂閱。MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);List<MonitoredItemCreateRequest> requests = new ArrayList<>();requests.add(request);//創(chuàng)建監(jiān)控項(xiàng),并且注冊(cè)變量值改變時(shí)候的回調(diào)函數(shù)。List<UaMonitoredItem> items = subscription.createMonitoredItems(TimestampsToReturn.Both,requests,(item,id)->{item.setValueConsumer((item, value)->{System.out.println("nodeid :"+item.getReadValueId().getNodeId());System.out.println("value :"+value.getValue().getValue());})}).get(); }

上面的代碼與之前的例子相比代碼量多了很多,下面我們就來(lái)解釋上面的代碼都發(fā)生了什么。

首先還是需要?jiǎng)?chuàng)建OPC連接,然后用OpcUaClient對(duì)象創(chuàng)建UaSubscription訂閱對(duì)象,方法.createSubscription()接受一個(gè)double類型的參數(shù),表示訂閱發(fā)布間隔,單位為毫秒。

接下來(lái)就是創(chuàng)建需要訂閱的變量。

NodeId nodeId = new NodeId(3,"\"test_value\""); ReadValueId readValueId = new ReadValueId(nodeId,AttributeId.Value.uid(),null,null);

然后創(chuàng)建監(jiān)控參數(shù)對(duì)象,監(jiān)控參數(shù)對(duì)象用于之后的創(chuàng)建監(jiān)控請(qǐng)求對(duì)象,創(chuàng)建訂閱需要用到監(jiān)控請(qǐng)求對(duì)象,MonitoringParameters的構(gòu)造函數(shù)如下:

public MonitoringParameters(UInteger clientHandle, Double samplingInterval, ExtensionObject filter, UInteger queueSize, Boolean discardOldest) {this.clientHandle = clientHandle;this.samplingInterval = samplingInterval;this.filter = filter;this.queueSize = queueSize;this.discardOldest = discardOldest; }

這里就接受最重要的兩個(gè)參數(shù)。

第一個(gè)參數(shù)clientHandle對(duì)象很重要,用來(lái)標(biāo)識(shí)每個(gè)創(chuàng)建的監(jiān)控項(xiàng),所以對(duì)于不同的監(jiān)控變量這個(gè)值必須不同,并且唯一。可以采用遞增的方式來(lái)設(shè)置這個(gè)值,或者在多線程環(huán)境下使用具有原子性的數(shù)據(jù)類型來(lái)設(shè)置該值。

第二個(gè)參數(shù)samplingInterval是變量的采樣周期,單位為毫秒。以S7-1500為例的話在PLC的組態(tài)設(shè)置里面也是可以設(shè)置采樣周期,所以暫不清楚這兩種設(shè)置方式是否會(huì)沖突。

好了,在創(chuàng)建了監(jiān)控變量ReadValueId對(duì)象和監(jiān)控參數(shù)對(duì)象MonitoringParameters后就可以用這兩個(gè)對(duì)象來(lái)創(chuàng)建監(jiān)控項(xiàng)請(qǐng)求對(duì)象MonitoredItemCreateRequest了,該對(duì)象構(gòu)造函數(shù)如下:

public MonitoredItemCreateRequest(ReadValueId itemToMonitor, MonitoringMode monitoringMode, MonitoringParameters requestedParameters) {this.itemToMonitor = itemToMonitor;this.monitoringMode = monitoringMode;this.requestedParameters = requestedParameters; }

可以看到構(gòu)造函數(shù)以剛剛我們創(chuàng)建的ReadValueId和MonitoringParameters對(duì)象作為形參。所以我們創(chuàng)建該對(duì)象也很簡(jiǎn)單

MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);

這樣就創(chuàng)建了一個(gè)監(jiān)控項(xiàng)創(chuàng)建請(qǐng)求對(duì)象。

因?yàn)镸onitoredItemCreateRequest對(duì)象包含了監(jiān)控的變量節(jié)點(diǎn)和監(jiān)控的參數(shù),所以接下來(lái)我們就可以用MonitoredItemCreateRequest來(lái)創(chuàng)建變量訂閱了,我們調(diào)用一開(kāi)始獲得的UaSubscription對(duì)象的createMonitoredItems()方法,該方法的簽名如下:

public interface UaSubscription {//...default CompletableFuture<List<UaMonitoredItem>> createMonitoredItems(TimestampsToReturn timestampsToReturn,List<MonitoredItemCreateRequest> itemsToCreate,BiConsumer<UaMonitoredItem, Integer> itemCreationCallback) {//...}//... }

可以看到,該方法接受一個(gè)MonitoredItemCreateRequest列表,如果有多個(gè)需要訂閱的變量就可以把所有需要監(jiān)控的對(duì)象都加入到該列表然后調(diào)用該方法來(lái)創(chuàng)建訂閱。如果只有一個(gè)訂閱的變量,那么把該變量的MonitoredItemCreateRequest對(duì)象加入一個(gè)List然后把這個(gè)List作為實(shí)參傳遞進(jìn)createMonitoredItems方法即可。

我們?cè)賮?lái)看第三個(gè)參數(shù),第三個(gè)參數(shù)是一個(gè)BiConsumer函數(shù)接口,該函數(shù)接口會(huì)在List<MonitoredItemCreateRequest>里每個(gè)監(jiān)控項(xiàng)創(chuàng)建成功后調(diào)用的函數(shù)接口。該函數(shù)提供了一個(gè)UaMonitoredItem參數(shù),我們用該參數(shù)可以訪問(wèn)到創(chuàng)建成功的監(jiān)控項(xiàng)的NodeId信息等等。

所以我們利用函數(shù)接口在創(chuàng)建監(jiān)控成功后,隨便為監(jiān)控項(xiàng)注冊(cè)變量值改變的回調(diào)函數(shù)。如下:

List<UaMonitoredItem> items = subscription.createMonitoredItems(TimestampsToReturn.Both,requests,(item,id)->{item.setValueConsumer((item, value)->{System.out.println("nodeid :"+item.getReadValueId().getNodeId());System.out.println("value :"+value.getValue().getValue());})} ).get();

上面例子中在創(chuàng)建成功的回調(diào)函數(shù)中對(duì)item調(diào)用setValueConsumer方法來(lái)設(shè)置變量值改變的回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)就是該變量每次發(fā)生改變后所調(diào)用的方法,這里的例子是變量改變時(shí)打印節(jié)點(diǎn)id和變量值到標(biāo)準(zhǔn)輸出中。

最后

到這里這篇結(jié)束OPC UA的java實(shí)現(xiàn)的Milo庫(kù)的文章就到此結(jié)束了,文章中提供了創(chuàng)建OPC客戶端對(duì)象以及變量瀏覽,讀,寫(xiě),和訂閱的具體例子。雖然這些都是很基本也很簡(jiǎn)單的操作,但是網(wǎng)上對(duì)于Milo庫(kù)的學(xué)習(xí)資源真的是少之又少,所以也希望能讓大家有一個(gè)概念,如果需要了解更高級(jí)的功能或更多關(guān)于Milo庫(kù)的架構(gòu)建議你去到Milo庫(kù)的Github倉(cāng)庫(kù)中的閱讀源代碼來(lái)了解更多更詳細(xì)的信息。


喜歡我們的文章也可以關(guān)注公眾號(hào)噢!

總結(jié)

以上是生活随笔為你收集整理的OPCUA标准java实现 Milo库的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。