问题描述
我正在使用 GOPCUA 库从 OPC UA 服务器 (KepServerEx) 获取数据。当我取消订阅而不关闭客户端连接时,有时代码会陷入尝试无限期创建安全通道的循环中,并且服务器继续发送带有代码 serviceFaultResponse
StatusBadNoSubscription (0x80790000)
以下是我正在使用的可以重现该问题的代码。它并不总是发生。
以下是启用调试的日志文件,用于代码正常工作时 (logs_ok.txt) 和不工作时 (logs_not_ok.txt)。
导致此问题的原因是什么 - 服务器、客户端库还是我的代码? 怎么解决?
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","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)
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)