Go OPC UA-此会话没有可用的订阅。StatusBadNoSubscription(0x80790000)
我正在使用库从OPC UA服务器()获取数据。当我在不关闭客户端连接的情况下取消订阅时,有时代码会陷入试图无限期创建安全通道的循环中,服务器会继续发送带有代码的Go OPC UA-此会话没有可用的订阅。StatusBadNoSubscription(0x80790000),go,opc-ua,opc,Go,Opc Ua,Opc,我正在使用库从OPC UA服务器()获取数据。当我在不关闭客户端连接的情况下取消订阅时,有时代码会陷入试图无限期创建安全通道的循环中,服务器会继续发送带有代码的serviceFaultResponse,StatusBadNoSubscription(0x80790000) 下面是我正在使用的代码,可以重现这个问题。这并不总是发生 下面是启用了调试的日志文件,用于代码何时工作正常()和何时不工作() 什么可能导致此问题-服务器、客户端库或我的代码? 如何解决呢 package main impor
serviceFaultResponse
,StatusBadNoSubscription(0x80790000)
下面是我正在使用的代码,可以重现这个问题。这并不总是发生
下面是启用了调试的日志文件,用于代码何时工作正常()和何时不工作()
什么可能导致此问题-服务器、客户端库或我的代码?
如何解决呢
package main
import (
"context"
"flag"
"fmt"
"log"
"time"
"github.com/gopcua/opcua"
"github.com/gopcua/opcua/debug"
"github.com/gopcua/opcua/ua"
)
func main() {
var (
endpoint = flag.String("endpoint", "opc.tcp://192.168.189.1:49320", "OPC UA Endpoint URL")
policy = flag.String("policy", "None", "Security policy: None, Basic128Rsa15, Basic256, Basic256Sha256. Default: None")
mode = flag.String("mode", "None", "Security mode: None, Sign, SignAndEncrypt. Default: None")
certFile = flag.String("cert", "", "Path to cert.pem. Required for security mode/policy != None")
keyFile = flag.String("key", "", "Path to private key.pem. Required for security mode/policy != None")
nodeID = flag.String("node", "ns=2;s=HONDA.DEV1.T1", "node id to subscribe to")
interval = flag.String("interval", opcua.DefaultSubscriptionInterval.String(), "subscription interval")
)
flag.BoolVar(&debug.Enable, "debug", true, "enable debug logging")
flag.Parse()
log.SetFlags(0)
subInterval, err := time.ParseDuration(*interval)
if err != nil {
log.Fatal(err)
}
// add an arbitrary timeout to demonstrate how to stop a subscription
// with a context.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
endpoints, err := opcua.GetEndpoints(ctx, *endpoint)
if err != nil {
log.Fatal(err)
}
ep := opcua.SelectEndpoint(endpoints, *policy, ua.MessageSecurityModeFromString(*mode))
if ep == nil {
log.Fatal("Failed to find suitable endpoint")
}
fmt.Println("*", ep.SecurityPolicyURI, ep.SecurityMode)
opts := []opcua.Option{
opcua.SecurityPolicy(*policy),
opcua.SecurityModeString(*mode),
opcua.CertificateFile(*certFile),
opcua.PrivateKeyFile(*keyFile),
opcua.AuthAnonymous(),
opcua.SecurityFromEndpoint(ep, ua.UserTokenTypeAnonymous),
}
c := opcua.NewClient(ep.EndpointURL, opts...)
if err := c.Connect(ctx); err != nil {
log.Fatal(err)
}
defer c.Close()
notifyCh := make(chan *opcua.PublishNotificationData)
sub, err := c.Subscribe(&opcua.SubscriptionParameters{
Interval: subInterval,
}, notifyCh)
if err != nil {
log.Fatal(err)
}
log.Printf("Created subscription with id %v", sub.SubscriptionID)
id, err := ua.ParseNodeID(*nodeID)
if err != nil {
log.Fatal(err)
}
miCreateRequest := opcua.NewMonitoredItemCreateRequestWithDefaults(id, ua.AttributeIDValue, uint32(42))
res, err := sub.Monitor(ua.TimestampsToReturnBoth, miCreateRequest)
if err != nil || res.Results[0].StatusCode != ua.StatusOK {
log.Fatal(err)
}
stop := make(chan int)
time.AfterFunc(5*time.Second, func(){
stop <- 0
})
breakLoop := false
for {
if breakLoop {
break
}
select {
case <-stop:
sub.Cancel()
breakLoop = true
case res := <-notifyCh:
if res.Error != nil {
log.Print(res.Error)
continue
}
switch x := res.Value.(type) {
case *ua.DataChangeNotification:
for _, item := range x.MonitoredItems {
data := item.Value.Value.Value()
log.Printf("MonitoredItem with client handle %v = %v", item.ClientHandle, data)
}
case *ua.EventNotificationList:
fmt.Println("Got an event, why ?")
default:
log.Printf("what's this publish result? %T", res.Value)
}
}
}
// doing some tasks here
time.Sleep(2*time.Second)
}
主程序包
进口(
“上下文”
“旗帜”
“fmt”
“日志”
“时间”
“github.com/gopcua/opcua”
“github.com/gopcua/opcua/debug”
“github.com/gopcua/opcua/ua”
)
func main(){
变量(
endpoint=flag.String(“endpoint”、“opc”。tcp://192.168.189.1:49320“,“OPC UA端点URL”)
policy=flag.String(“策略”、“无”、“安全策略:无、Basic128Rsa15、Basic256、Basic256Sha256。默认值:无”)
mode=flag.String(“mode”、“None”、“安全模式:None、Sign、SignAndEncrypt.Default:None”)
certFile=flag.String(“cert”,“”,“安全模式/策略所需的cert.pem.路径!=None”)
keyFile=flag.String(“key”、“”、“private key.pem.的路径,安全模式/策略所需!=None”)
nodeID=flag.String(“节点”,“ns=2;s=HONDA.DEV1.T1”,“要订阅的节点id”)
interval=flag.String(“interval”,opcua.DefaultSubscriptionInterval.String(),“subscription interval”)
)
flag.BoolVar(&debug.Enable,“debug”,true,“Enable debug logging”)
flag.Parse()
log.SetFlags(0)
子间隔,错误:=time.ParseDuration(*interval)
如果错误!=零{
log.Fatal(错误)
}
//添加任意超时以演示如何停止订阅
//有背景的。
ctx,cancel:=context.WithCancel(context.Background())
推迟取消
端点,err:=opcua.GetEndpoints(ctx,*endpoint)
如果错误!=零{
log.Fatal(错误)
}
ep:=opcua.SelectEndpoint(端点、*策略、ua.MessageSecurityModeFromString(*模式))
如果ep==nil{
log.Fatal(“未能找到合适的端点”)
}
fmt.Println(“*”,ep.SecurityPolicyURI,ep.SecurityMode)
选项:=[]opcua.Option{
opcua.安全政策(*政策),
opcua.SecurityModeString(*模式),
opcua.CertificateFile(*certFile),
opcua.PrivateKeyFile(*keyFile),
opcua.AuthAnonymous(),
opcua.SecurityFromEndpoint(ep、ua.UserTokenTypeAnonymous),
}
c:=opcua.NewClient(ep.EndpointURL,opts…)
如果错误:=c.Connect(ctx);错误!=nil{
log.Fatal(错误)
}
推迟c.结束()
notifyCh:=make(chan*opcua.PublishNotificationData)
sub,err:=c.Subscribe(&opcua.SubscriptionParameters){
区间:子区间,
},notifyCh)
如果错误!=零{
log.Fatal(错误)
}
log.Printf(“创建了id为%v的订阅”,sub.SubscriptionID)
id,err:=ua.ParseNodeID(*nodeID)
如果错误!=零{
log.Fatal(错误)
}
miCreateRequest:=opcua.NewMonitoredItemCreateRequestWithDefaults(id,ua.AttributeIDValue,uint32(42))
res,err:=sub.Monitor(ua.TimestampStoreTurnTworth,miCreateRequest)
如果错误!=nil | | res.Results[0]。状态代码!=ua.StatusOK{
log.Fatal(错误)
}
停止:=make(chan int)
time.AfterFunc(5*time.Second,func(){
停止