### 概述

本手册使用一台SX21作为ACP服务器，Ubuntu电脑作为客户端来读取、写入和订阅PLC变量功能。如下图所示：
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021345543b5.png)

下表概述了本手册各个产品组件

| **产品组件**                       | **描述说明**         |
| ------------------------------ | ---------------- |
| DeviceManager\_0.0.1.9         | 工智机插件安装管理器       |
| acpsymbollib\_1.0.1\_amd64.deb | Ubuntu客户端deb组件   |
| libacp\_0.2.3\_amd64.deb       | acpsymbollib依赖文件 |
| CppAcpServer.projectarchive    | PLC工程存档          |
| AcpClient.cpp                  | Linux客户端C++示例程序  |

---

### 安装卸载

**安装要求**

* 中科时代出厂的工智机的自带系统；
* 工智机可以访问互联网；
* Ubuntu系统客户端可以访问互联网；



**安装过程**

 **1、工智机安装acpplcaccess.deb组件**

1.打开Device Manager软件，使用工智机固定网口与个人电脑通讯。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021378b8bf8.png)

2.初次使用，需要安装ACP通讯服务。点击左下角“安装ACP服务”。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802137f72adc.png)

3.输入工智机固定IP地址、端口、用户名和密码后，点击“在线安装”。

| **IP地址** | 192.168.1.200 |
| -------- | ------------- |
| **端口**   | 2224          |
| **用户名**  | sinsegye      |
| **密码**   | 1             |

![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213874d53e.png)

等待安装完成。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802138e652af.png)

4.安装完成后，点击“扫描”，即可扫描出固定网口192.168.1.200连接的工智机。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021395ba818.png)

点击进入工智机后，左下角显示“已连接”状态。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802139ca6436.png)

5.点击“安装RTE插件服务”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213a4c1e32.png)

6.输入用户名：sinsegye，密码：1，点击“在线安装”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213ab756c5.png)

7.安装完成后，点击“软件”，在下拉菜单下选择“组件管理”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213b440f55.png)
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213bb54857.png)

8.点击浏览，可以在线浏览可以安装的组件。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213c71b172.png)

9.在组件中找到“SF1000-acpplcaccess”--点击“安装”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213cf65701.png)

10.等待deb包传送到工智机中，传送完成后点击“确定”进行安装。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213d85ad0e.png)

11.安装完成后，点击“确认”重启生效。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213dfc8c9c.png)

12.安装完成后，可以在“本地”页面浏览到SF1000-acpplcaccess已安装成功。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213e9a0a8a.png)

**2、Ubuntu 20.04电脑安装acpsymbollib和libacp库文件**

将官网下载的acpsymbollib\_1.0.1\_amd64.deb文件和libacp\_0.2.3\_amd64.deb文件拷贝到Ubuntu客户端/home文件夹下。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680213f77c0b7.png)

打开Ubuntu终端，安装acpsymbollib\_1.0.1\_amd64.deb
```shell
sudo dpkg -i acpsymbollib\_1.0.1\_amd64.deb
```
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802140f43aa1.png)

安装libacp\_0.2.3\_amd64.deb

```shell
sudo dpkg -i libacp\_0.2.3\_amd64.deb
```
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680214e73676c.png)

 **3、Ubuntu安装VScode**

使用Ubuntu Sofeware 安装VScode。没有Ubuntu-soft先使用命令下载。
```shell
sudo apt-get update&#xA;sudo apt -y install ubuntu-software
```

![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680214ffe3366.png)


打开VScode，点击“Extensions”。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802150c425b4.png)

搜索“chinese”—— 选择中文（简体）—— 安装
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802151700400.png)

搜索“C++”——点击安装
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802151f9f589.png)


重启Ubuntu系统。

**、设置VScode C++编译环境**

Ubuntu打开VScode软件，点击“选择我的默认编辑器”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802153363b77.png)

选择使用g++编译器
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802153eef965.png)

点击“打开文件夹”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680215506a7e8.png)

新建一个文件夹
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021578e03bf.png)

点击“OPEN”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802158900d52.png)

点击“信任作者”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021594eb193.png)

新建一个cpp文件
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802159fdf9f2.png)


编写测试程序

```shell
#include\<iostream>
using namespace std;
int main(void)
{
cout<<"Hello"<\<endl;
return 0；
} 
```
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021611c0ce6.png)

点击“终端”——“配置默认生成任务”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802161a5b555.png)


选择“g++生成活动文件”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021626e03ba.png)

添加“-lacpsymbollib”和“-lacpsymbolapi-c”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021630a7ae9.png)

点击“运行生成任务”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021639a572b.png)

点击“运行”——“添加配置”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680216428dcac.png)

选择“C++”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680216516638c.png)


点击“添加配置”——“（gdb）启动”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802165a08ace.png)

修改“program”参数为"**${fileDirname}/${fileBasenameNoExtension}**"
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680216658c4ee.png)
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802166eb816e.png)

同时，添加属性“preLaunchTask”：“C/C++: g++ 生成活动文件”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802167cc5d44.png)

选择Hello.cpp文件——调试，可以在终端看到调试结果。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802168ab8c72.png)

**更新安装**

 **1.ACP服务器更新acpplcaccess组件**

在插件管理器Device Mananger--组件管理--本地组件中，点击SF1000-acpplcaccess，选择可更新的版本后，点击“更新”。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802169c4d2e7.png)

**2.Linux系统更新acpsymbollib和libacp库文件**

从中科时代官网下载最新的acpsymbollib和libacp库文件，使用dpkg -i 重新安装

```shell
sudo dpkg -i acpsymbollib\_1.0.1\_amd64.deb&#xA;sudo dpkg -i libacp\_0.2.3\_amd64.deb 
```

**卸载过程**

**1. ACP服务器卸载acpplcaccess组件**

在插件管理器Device Mananger--组件管理--本地组件中，点击SF1000-acpplcaccess，选择“卸载”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680216c1456a6.png)

点击“确定”
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680216d15c90b.png)

卸载成功后，点击“确定”重启生效。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680216db56572.png)

卸载成功后，“本地”页面组件消失。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680216e3d9952.png)

 **2、卸载Ubuntu客户端acpsymbollib和libacp库文件**

使用dpkg -r命令进行卸载

```shell
sudo dpkg -r acpsymbollib&#xA;sudo dpkg -r libacp
```
重启
```shell
sudo reboot 
```


 **3、Ubuntu客户端卸载VScode**

使用Ubuntu-Software卸载VScode
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802170cf3de3.png)

---
### 技术说明

**快速启动**

**（一）本例软、硬件配置**


| 硬件：|软件 |
| - | - |
|工智机SX21 | 插件管理器DeviceManager_0.0.1.9|
|Ubuntu 20.04系统客户端 |客户端组件acpsymbollib_1.0.1_amd64.deb |
|个人电脑 |依赖库文件libacp_0.2.3_amd64.deb |
| |服务端PLC工程存档CppAcpServer.projectarchive|
| |客户端C++测试程序AcpClient.cpp |
| |中科时代IDE MetaFacture V1.0.6.6 |


**（二）本例实验操作步骤**


**1.实验要求**

a.工智机使用插件管理器成功安装acpplcaccess组件；

b.Linux系统客户端安装acpsymbollib和liblibacp库文件；

c.Linux系统客户端安装VScode软件，并配置C++编译环境。


**2.实验原理图**

![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680217a0cc3ce.png)

**3.实验步骤**

3.1 解压官网下载的工程存档文件“CppAcpServer.projectarchive”，登录工智机，下载运行程序。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680217a9777d0.png)

3.2 将官网下载的C++程序“AcpClient.cpp”拷贝到Ubuntu的Project文件夹中
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680217b140123.png)

3.3 在VScode中选择AcpClient.cpp程序，在main()函数中取消ReadSymbol()注释
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680217b918c6e.png)

修改程序ReadSymbol()中的工智机IP地址：
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680217c2773e9.png)

3.4 点击Debug，读取PLC\_PRG程序中的变量
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/680217cc0a9f7.png)

修改程序WriteSymbol()中的工智机IP地址：

![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802183d6f983.png)

3.5 在main()函数中注释ReadSymbol()，取消Writesymbol()注释。点击Debug，写入变量值。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802184ba0e93.png)

查看工智机的PLC变量值，写入成功。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021854dcc45.png)

3.6 在main()函数中注释Writesymbol()，取消SubSymbol()注释。点击Debug，订阅变量。
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/6802185c79994.png)

修改程序SubSymbol()中的工智机IP地址：
![](https://resource.helplook.net/docker_production/3648ne/article/fqXAuxwB/68021863973fe.png)


订阅的变量数值不断在变化。

---
### **示例**

#### **读取变量**

通过实例化的connParam结构传递TCP连接参数和IP地址，使用AcpCreatConnHandler获得连接句柄。
创建读取变量结构体，设定变量类型，读取路径和读取字符大小，使用AcpReadTagList进行读取。

详细参数说明见**功能介绍**。
```shell
void ReadSymbol()
{
  ConnParam connParam;
  connParam.connType = AcpConnType::ACP_CONN_TYPE_TCP;
  const char* ipAddress = "192.168.110.114";
  strncpy(connParam.szConnParam, ipAddress, sizeof(connParam.szConnParam) - 1);
  connParam.szConnParam[sizeof(connParam.szConnParam) - 1] = '\0';  // 确保以 null 结尾

  auto handle = AcpCreatConnHandler(&connParam);

    TagInfo readinfo[15];

    ST_BOOL bool1_ = false;
    std::string strBoolPath = "Application.PLC_PRG.xVar1";

    ST_BYTE byte1_ = 0;
    std::string strBytePath = "Application.PLC_PRG.bVar2";

    ST_WORD word1_=0;
    std::string strWordPath = "Application.PLC_PRG.wVar3";

    ST_DWORD dword1_=0;
    std::string strDwordPath = "Application.PLC_PRG.dwVar4";

    ST_LWORD lword1_=0;
    std::string strLwordPath = "Application.PLC_PRG.lwVar5";

    ST_SINT sint1_=0;
    std::string strSintPath = "Application.PLC_PRG.siVar6";

    ST_USINT usint1_=0;
    std::string strUsintPath = "Application.PLC_PRG.usiVar7";

    ST_INT int1_=0;
    std::string strIntPath = "Application.PLC_PRG.iVar8";

    ST_UINT uint1_=0;
    std::string strUintPath = "Application.PLC_PRG.uiVar9";

    ST_DINT dint1_=0;
    std::string strDintPath = "Application.PLC_PRG.diVar10";

    ST_UDINT udint1_=0;
    std::string strUdintPath = "Application.PLC_PRG.udiVar11";

    ST_LINT lint1_=0;
    std::string strLintPath = "Application.PLC_PRG.liVar12";

    ST_REAL real1_=0;
    std::string strRealPath = "Application.PLC_PRG.rVar13";

    ST_LREAL lreal1_=0;
    std::string strLrealPath = "Application.PLC_PRG.lrVar14";

    ST_STRING str[81];
    std::string strStringPath = "Application.PLC_PRG.sVar15";

    readinfo[0].tagDesc.szSymbolFullName = strBoolPath.c_str();
    readinfo[0].tagValue.pValueData = &bool1_;
    readinfo[0].tagValue.nValueSize = sizeof(ST_BOOL);

    readinfo[1].tagDesc.szSymbolFullName = strBytePath.c_str();
    readinfo[1].tagValue.pValueData = &byte1_;
    readinfo[1].tagValue.nValueSize = sizeof(ST_BYTE);

    readinfo[2].tagDesc.szSymbolFullName = strWordPath.c_str();
    readinfo[2].tagValue.pValueData = &word1_;
    readinfo[2].tagValue.nValueSize = sizeof(ST_WORD);

    readinfo[3].tagDesc.szSymbolFullName = strDwordPath.c_str();
    readinfo[3].tagValue.pValueData = &dword1_;
    readinfo[3].tagValue.nValueSize = sizeof(ST_DWORD);

    readinfo[4].tagDesc.szSymbolFullName = strLwordPath.c_str();
    readinfo[4].tagValue.pValueData = &lword1_;
    readinfo[4].tagValue.nValueSize = sizeof(ST_LWORD);

    readinfo[5].tagDesc.szSymbolFullName = strSintPath.c_str();
    readinfo[5].tagValue.pValueData = &sint1_;
    readinfo[5].tagValue.nValueSize = sizeof(ST_SINT);

    readinfo[6].tagDesc.szSymbolFullName = strUsintPath.c_str();
    readinfo[6].tagValue.pValueData = &usint1_;
    readinfo[6].tagValue.nValueSize = sizeof(ST_USINT);

    readinfo[7].tagDesc.szSymbolFullName = strIntPath.c_str();
    readinfo[7].tagValue.pValueData = &int1_;
    readinfo[7].tagValue.nValueSize = sizeof(ST_INT);

    readinfo[8].tagDesc.szSymbolFullName = strUintPath.c_str();
    readinfo[8].tagValue.pValueData = &uint1_;
    readinfo[8].tagValue.nValueSize = sizeof(ST_UINT);

    readinfo[9].tagDesc.szSymbolFullName = strDintPath.c_str();
    readinfo[9].tagValue.pValueData = &dint1_;
    readinfo[9].tagValue.nValueSize = sizeof(ST_DINT);

    readinfo[10].tagDesc.szSymbolFullName = strUdintPath.c_str();
    readinfo[10].tagValue.pValueData = &udint1_;
    readinfo[10].tagValue.nValueSize = sizeof(ST_UDINT);

    readinfo[11].tagDesc.szSymbolFullName = strLintPath.c_str();
    readinfo[11].tagValue.pValueData = &lint1_;
    readinfo[11].tagValue.nValueSize = sizeof(ST_LINT);

    readinfo[12].tagDesc.szSymbolFullName = strRealPath.c_str();
    readinfo[12].tagValue.pValueData = &real1_;
    readinfo[12].tagValue.nValueSize = sizeof(ST_REAL);

    readinfo[13].tagDesc.szSymbolFullName = strLrealPath.c_str();
    readinfo[13].tagValue.pValueData = &lreal1_;
    readinfo[13].tagValue.nValueSize = sizeof(ST_LREAL);

    readinfo[14].tagDesc.szSymbolFullName = strStringPath.c_str();
    readinfo[14].tagValue.pValueData = &str;
    readinfo[14].tagValue.nValueSize = sizeof(str);
     
    auto var_size = sizeof(readinfo) / sizeof(TagInfo);
    auto result = AcpReadTagList(handle, &readinfo[0], var_size, 500);

    if (result != false)
    {
      printf("读取变量失败!\n");
    } 
    else 
    {
      printf("读取变量成功!\n");
      printf("xVar1=%d\n",bool1_);
      printf("bVar2=%d\n",byte1_);
      printf("wVar3=%d\n",word1_);
      printf("dwVar4=%u\n",dword1_);
      printf("lwVar5=%ld\n",lword1_);
      printf("siVar6=%d\n",sint1_);
      printf("usiVar7=%d\n",usint1_);
      printf("iVar8=%d\n",int1_);
      printf("uiVar9=%d\n",uint1_);
      printf("diVar10=%d\n",dint1_);
      printf("udiVar11=%u\n",udint1_);
      printf("liVar12=%ld\n",lint1_);
      printf("rVar13=%f\n",real1_);
      printf("lrVar14=%.8lf\n",lreal1_);
      printf("sVar15=%s \n",str);
    }
}
```


#### **写入变量**

通过实例化的connParam结构传递TCP连接参数和IP地址，使用AcpCreatConnHandler获得连接句柄。
创建写入变量结构体，设定变量类型，写入路径和写入字符大小，使用AcpWriteTagList进行读取。

详细参数说明见**功能介绍**。
```shell
void WriteSymbol()
{
  ConnParam connParam;
  connParam.connType = AcpConnType::ACP_CONN_TYPE_TCP;
  const char* ipAddress = "192.168.110.114";
  strncpy(connParam.szConnParam, ipAddress, sizeof(connParam.szConnParam) - 1);
  connParam.szConnParam[sizeof(connParam.szConnParam) - 1] = '\0';  // 确保以 null 结尾

  auto handle = AcpCreatConnHandler(&connParam);

    TagInfo writeinfo[15];

    ST_BOOL bool1_ = false;
    std::string strBoolPath = "Application.PLC_PRG.xVar1";

    ST_BYTE byte1_ = 27;
    std::string strBytePath = "Application.PLC_PRG.bVar2";

    ST_WORD word1_=55533;
    std::string strWordPath = "Application.PLC_PRG.wVar3";

    ST_DWORD dword1_=4000000000;
    std::string strDwordPath = "Application.PLC_PRG.dwVar4";

    ST_LWORD lword1_=6666666666;
    std::string strLwordPath = "Application.PLC_PRG.lwVar5";

    ST_SINT sint1_=-88;
    std::string strSintPath = "Application.PLC_PRG.siVar6";

    ST_USINT usint1_=222;
    std::string strUsintPath = "Application.PLC_PRG.usiVar7";

    ST_INT int1_=-32666;
    std::string strIntPath = "Application.PLC_PRG.iVar8";

    ST_UINT uint1_=33355;
    std::string strUintPath = "Application.PLC_PRG.uiVar9";

    ST_DINT dint1_=2121212121;
    std::string strDintPath = "Application.PLC_PRG.diVar10";

    ST_UDINT udint1_=3000000000;
    std::string strUdintPath = "Application.PLC_PRG.udiVar11";

    ST_LINT lint1_=8888888888;
    std::string strLintPath = "Application.PLC_PRG.liVar12";

    ST_REAL real1_=543.9876;
    std::string strRealPath = "Application.PLC_PRG.rVar13";

    ST_LREAL lreal1_=678.1234567;
    std::string strLrealPath = "Application.PLC_PRG.lrVar14";

    ST_STRING str[81];
    const char* source = "Sinsegye and sinsegye";
    strcpy(str, source);  // NOLINT
    std::string strStringPath = "Application.PLC_PRG.sVar15";


    writeinfo[0].tagDesc.szSymbolFullName = strBoolPath.c_str();
    writeinfo[0].tagValue.pValueData = &bool1_;
    writeinfo[0].tagValue.nValueSize = sizeof(ST_BOOL);

    writeinfo[1].tagDesc.szSymbolFullName = strBytePath.c_str();
    writeinfo[1].tagValue.pValueData = &byte1_;
    writeinfo[1].tagValue.nValueSize = sizeof(ST_BYTE);

    writeinfo[2].tagDesc.szSymbolFullName = strWordPath.c_str();
    writeinfo[2].tagValue.pValueData = &word1_;
    writeinfo[2].tagValue.nValueSize = sizeof(ST_WORD);

    writeinfo[3].tagDesc.szSymbolFullName = strDwordPath.c_str();
    writeinfo[3].tagValue.pValueData = &dword1_;
    writeinfo[3].tagValue.nValueSize = sizeof(ST_DWORD);

    writeinfo[4].tagDesc.szSymbolFullName = strLwordPath.c_str();
    writeinfo[4].tagValue.pValueData = &lword1_;
    writeinfo[4].tagValue.nValueSize = sizeof(ST_LWORD);

    writeinfo[5].tagDesc.szSymbolFullName = strSintPath.c_str();
    writeinfo[5].tagValue.pValueData = &sint1_;
    writeinfo[5].tagValue.nValueSize = sizeof(ST_SINT);

    writeinfo[6].tagDesc.szSymbolFullName = strUsintPath.c_str();
    writeinfo[6].tagValue.pValueData = &usint1_;
    writeinfo[6].tagValue.nValueSize = sizeof(ST_USINT);

    writeinfo[7].tagDesc.szSymbolFullName = strIntPath.c_str();
    writeinfo[7].tagValue.pValueData = &int1_;
    writeinfo[7].tagValue.nValueSize = sizeof(ST_INT);

    writeinfo[8].tagDesc.szSymbolFullName = strUintPath.c_str();
    writeinfo[8].tagValue.pValueData = &uint1_;
    writeinfo[8].tagValue.nValueSize = sizeof(ST_UINT);

    writeinfo[9].tagDesc.szSymbolFullName = strDintPath.c_str();
    writeinfo[9].tagValue.pValueData = &dint1_;
    writeinfo[9].tagValue.nValueSize = sizeof(ST_DINT);

    writeinfo[10].tagDesc.szSymbolFullName = strUdintPath.c_str();
    writeinfo[10].tagValue.pValueData = &udint1_;
    writeinfo[10].tagValue.nValueSize = sizeof(ST_UDINT);

    writeinfo[11].tagDesc.szSymbolFullName = strLintPath.c_str();
    writeinfo[11].tagValue.pValueData = &lint1_;
    writeinfo[11].tagValue.nValueSize = sizeof(ST_LINT);

    writeinfo[12].tagDesc.szSymbolFullName = strRealPath.c_str();
    writeinfo[12].tagValue.pValueData = &real1_;
    writeinfo[12].tagValue.nValueSize = sizeof(ST_REAL);

    writeinfo[13].tagDesc.szSymbolFullName = strLrealPath.c_str();
    writeinfo[13].tagValue.pValueData = &lreal1_;
    writeinfo[13].tagValue.nValueSize = sizeof(ST_LREAL);

    writeinfo[14].tagDesc.szSymbolFullName = strStringPath.c_str();
    writeinfo[14].tagValue.pValueData = &str;
    writeinfo[14].tagValue.nValueSize = sizeof(str);

    auto var_size = sizeof(writeinfo) / sizeof(TagInfo);
    auto result = AcpWriteTagList(handle, &writeinfo[0], var_size, 500);

     if (result != false) 
     {
      printf("写入变量失败!\n");
     }
     else
     {
      printf("写入变量成功!\n");
     }
}
```

#### **订阅变量**

通过实例化的connParam结构传递TCP连接参数和IP地址，使用AcpCreatConnHandler获得连接句柄。
使用AcpRegisterNotifyCallBack注册回调函数NotifyCallback；
创建订阅变量结构体，设定订阅变量路径，使用AcpAddTagsNotification添加订阅变量列表。

详细参数说明见**功能介绍**。
```shell
void SubSymbol() {
  ConnParam connParam;
  const char* ipAddress = "192.168.110.114";
  strncpy(connParam.szConnParam, ipAddress, sizeof(connParam.szConnParam) - 1);
  connParam.szConnParam[sizeof(connParam.szConnParam) - 1] = '\0';  // 确保以 null 结尾

  auto handle = AcpCreatConnHandler(&connParam);
  auto result = AcpRegisterNotifyCallBack(handle, NotifyCallback, nullptr);//注册回调函数

  TagInfo symbol[15];
 
  std::string str0 =  "Application.GVL.BOOL1";
  std::string str1 =  "Application.GVL.BYTE2";
  std::string str2 =  "Application.GVL.WORD3";
  std::string str3 =  "Application.GVL.DWORD4";
  std::string str4 =  "Application.GVL.LWORD5";
  std::string str5 =  "Application.GVL.SINT6";
  std::string str6 =  "Application.GVL.USINT7";
  std::string str7 =  "Application.GVL.INT8";
  std::string str8 =  "Application.GVL.UINT9";
  std::string str9 =  "Application.GVL.DINT10";
  std::string str10 = "Application.GVL.UDINT11";
  std::string str11 = "Application.GVL.LINT12";
  std::string str12 = "Application.GVL.REAL13";
  std::string str13 = "Application.GVL.LREAL14";
  std::string str14 = "Application.GVL.STRING15";
  symbol[0].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str0.c_str()));
  symbol[1].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str1.c_str()));
  symbol[2].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str2.c_str()));
  symbol[3].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str3.c_str()));
  symbol[4].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str4.c_str()));
  symbol[5].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str5.c_str()));
  symbol[6].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str6.c_str()));
  symbol[7].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str7.c_str()));
  symbol[8].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str8.c_str()));
  symbol[9].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str9.c_str()));
  symbol[10].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str10.c_str()));
  symbol[11].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str11.c_str()));
  symbol[12].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str12.c_str()));
  symbol[13].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str13.c_str()));
  symbol[14].tagDesc.szSymbolFullName = static_cast<const char*>(const_cast<char*>(str14.c_str()));
  
  auto nameSize = sizeof(symbol) / sizeof(TagInfo);
  
  int reqid = 6;                //订阅ID
  TagSubParam subParam;
  subParam.nIntervalMs = 15;    //订阅间隔时间
  subParam.nRequestId = reqid; //订阅ID
  result = AcpAddTagsNotification(handle, &symbol[0], nameSize, &subParam, 500);//添加订阅
}
```

#### **回调函数**

当订阅变量的值发生改变，进入回调函数。判断返回的变量名，将数值赋给相应的变量。
```shell
void NotifyCallback(TagSubInfo* pTagSubInfos, void* lpContext) {

ST_BOOL Subbool1=false;
ST_BYTE Subbyte1=0;
ST_WORD Subword1=0;
ST_DWORD Subdword1=0;
ST_LWORD Sublword1=0;
ST_SINT Subsint1=0;
ST_USINT Subusint1=0;
ST_INT Subint1= 0;
ST_UINT Subuint1=0;
ST_DINT Subdint1=0;
ST_UDINT Subudint1=0;
ST_LINT Sublint1=0;
ST_REAL Subreal1= 0;
ST_LREAL Sublreal1=0;
ST_STRING Substring1[80]="";

  if (pTagSubInfos->enReplyType == AcpSubReplyType::subscribefailed) 
  {
    printf("订阅失败! \n");
    if (pTagSubInfos->subFailSize > 0) 
    {
      printf("订阅失败的变量: ");
      for (uint64_t i = 0; i < pTagSubInfos->subFailSize; i++)
      {
        std::string name = std::string(pTagSubInfos->subFailTagsInfo[i].tagDesc.szSymbolFullName);
        printf("%s ", name.c_str());
      }
      printf("\n");
    }
  }
  else if (pTagSubInfos->enReplyType == AcpSubReplyType::subscribedelok) 
  {
    printf("取消订阅成功! \n");
  } 
  else if (pTagSubInfos->enReplyType == AcpSubReplyType::subscribeNotify)
  {
    printf("symbolSubReply->symbolSize:%d\n", pTagSubInfos->subOkSize);
    for (uint64_t i = 0; i < pTagSubInfos->subOkSize; i++) 
    {
      
      auto itemName = std::string(pTagSubInfos->subOkTagsInfo[i].tagDesc.szSymbolFullName);

      if (itemName == "Application.GVL.BOOL1") 
      {
        memcpy(&Subbool1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.BOOL1: %d\n", Subbool1);
      } 
      else if (itemName == "Application.GVL.BYTE2") 
      {
        memcpy(&Subbyte1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.BYTE2: %d\n", Subbyte1);
      }
      else if (itemName == "Application.GVL.WORD3") 
      {
        memcpy(&Subword1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.WORD3: %d\n", Subword1);
      }
      else if (itemName == "Application.GVL.DWORD4") 
      {
        memcpy(&Subdword1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.DWORD4: %u\n", Subdword1);
      }
      else if (itemName == "Application.GVL.LWORD5") 
      {
        memcpy(&Sublword1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.LWORD5: %ld\n", Sublword1);
      }
      else if (itemName == "Application.GVL.SINT6") 
      {
        memcpy(&Subsint1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.SINT6: %d\n", Subsint1);
      }
      else if (itemName == "Application.GVL.USINT7") 
      {
        memcpy(&Subusint1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.USINT7: %d\n", Subusint1);
      }
      else if (itemName == "Application.GVL.INT8") 
      {
        memcpy(&Subint1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.INT8: %d\n", Subint1);
      }
      else if (itemName == "Application.GVL.UINT9") 
      {
        memcpy(&Subuint1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.UINT9: %d\n", Subuint1);
      }
      else if (itemName == "Application.GVL.DINT10") 
      {
        memcpy(&Subdint1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.DINT10: %d\n", Subdint1);
      }
      else if (itemName == "Application.GVL.UDINT11") 
      {
        memcpy(&Subudint1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.UDINT11: %u\n", Subudint1);
      }
      else if (itemName == "Application.GVL.LINT12") 
      {
        memcpy(&Sublint1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.LINT12: %ld\n", Sublint1);
      }
      else if (itemName == "Application.GVL.REAL13") 
      {
        memcpy(&Subreal1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.REAL13: %f\n", Subreal1);
      }
      else if (itemName == "Application.GVL.LREAL14") 
      {
        memcpy(&Sublreal1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.LREAL14: %lf\n", Sublreal1);
      }
      else if (itemName == "Application.GVL.STRING15") 
      {
        memcpy(&Substring1, pTagSubInfos->subOkTagsInfo[i].tagValue.pValueData,
               pTagSubInfos->subOkTagsInfo[i].tagValue.nValueSize);
        printf("Application.GVL.STRING15: %s\n", Substring1);
      }

    }
  }
}
```



#### **主函数**

取消相应的注释来调用读取变量、写入变量和订阅变量的方法。
```C++
int main() {
  //ReadSymbol();//读取变量
  //WriteSymbol();//写入变量
  //SubSymbol();//订阅变量
  while (1) 
  {
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));//暂停1s
  }
  return 0;
}
```