Client与Server是通过安全通道进行通信(可参阅官方文档Part 2),英文叫Secure Channel,
在Client的默认配置中,安全通道的超时时间是10分钟,超过10分钟后就会与Server断开连接,如下,
但是大部分情况下我们都想一直连着,是否断开由Client来决定。直观的方法是把这个超时时间改大点,但是治标不治本。经过本人查看源码,发现有个比较好的方法,下面简单描述一下。
保持连接方法
方法的原理就是Client在Server端添加一个订阅,然后每隔1秒钟Client向Server发送一个publish请求,server就会返回一个keep alive的response。详细操作可以参考这篇文章
Client代码如下,这里为了方便测试,把安全通道的超时时间改为10秒,
#include <stdlib.h>
#include "open62541.h"
UA_Boolean running = true;
static void stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
int main(void)
{
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Client *client = UA_Client_new();
UA_ClientConfig *cc = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(cc);
cc->secureChannelLifeTime = 10000; // 安全通道超时时间改为10s
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
if(retval != UA_STATUSCODE_GOOD) {
UA_Client_delete(client);
return (int)retval;
}
// ----------------------------- 添加订阅 --------------------------------
UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
/* Force the server to send keep alive responses every second to trigger
* the client to send new publish requests. Requests from the client
* will make the server to change to the new SecurityToken after renewal.
*/
request.requestedPublishingInterval = 1000; // publish间隔设置为1s
request.requestedMaxKeepAliveCount = 1;
UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
NULL, NULL, NULL);
UA_CreateSubscriptionResponse_clear(&response);
// -----------------------------------------------------------------------
while (running)
{
UA_Client_run_iterate(client, 0);
}
/* Clean up */
UA_Client_delete(client); /* Disconnects the client internally */
return EXIT_SUCCESS;
}
server端代码如下,
#include "open62541.h"
#include <signal.h>
#include <stdlib.h>
UA_Boolean running = true;
static void stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
int main(void)
{
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
如何组织工程以及编译链接就不说了,可以参考之前的系列文章,最后编译ok后,先运行Server,再运行Client,
Client这边的打印如下,
可以看到Client端每隔大约7.5秒会重新创建安全通道,而Server端这边会一直保持连接状态。
为什么是7.5秒呢?因为UA_Client_run_iterate()会在0.75*secureChannelLifeTime时重新创建安全通道,更新SecurityToken,这个也是官方文档中规定的(官方文档Part 4)。
总结
本文主要讲述Client如何在安全通道的超时时间到达前自动重新创建安全通道,并保持和Server的连接。解决办法也是在源码里的测试用例里发现的。
如果有写的不对的地方,希望能留言指正,谢谢阅读。