EPICS通道访问介绍以及练习

news/2024/5/20 22:15:45

提纲

1) 通道访问概念

2)通道访问API

3) 简单的CA客户端

4)使用回调的简单CA客户端

EPICS概要

搜索和连接过程

搜索请求

1)搜索请求由一系列UDP包组成

  • 只发送给EPICS_CA_ADDR_LIST
  • 从短时间间隔开始,每次加倍
  • 直到它变得大于5秒,接着它保持在5s
  • 在100个包后停止或者它得到了响应
  • 在它见到一个异常beacon或者创建一个新PV前,不再尝试
  • 发完所有100个包的全部时间大约8分钟

2)服务程序必须为每个包进行一次存在测试

3)通常在首个活前几个包时连接

4)不存在的PVs产生大量流量:尝试消除它们

Beacons

1) 一个beacon是一个由服务程序发送的UDP广播包。

2)当它健康时,每个服务程序以规则间隔发送一个UDP广播包(像一个心跳)

EPICS_CA_BEACON_PERIOD默认15秒。

3)当它启动时,每个服务程序广播一个启动序列的UDP beacons

  • 从短间隔开始(25ms, 对于vxWorks 75ms)
  • 每次间隔加倍
  • 直到它变得大于15s,接着它保持在15s。发出大于10个beacons和40s变成准备状态

4) 客户端监视这些beacons

  • 确定连接状态,是否再次发送搜索

虚电路断开

1) 3.13和早期3.14

  • 挂断消息或者30秒内无来自服务程序的响应。
  • 如果不是一个挂断,则客户端发送"你在吗"的请求。
  • 如果5秒无响应,TCP连接被关闭
  • MEDM窗口变白。
  • 客户端再次发送搜索请求

2)3.14.5以及以后

  • 来自服务程序的挂断消息。
  • TCP连接被关闭
  • MEDM变白
  • 客户端再次发送搜索请求

虚拟电路无响应

3.14.5以及以后

1)30秒内无来自服务程序的响应。

2)客户端接着发送"你在吗"的请求

3)如果5秒内无响应,TCP连接不被关闭,至少若干小时

4)MEDM窗口变白

5)客户端不重新发送搜索请求,有利于网络风暴

6)不调用ca_poll的客户端经常见到虚电路断开,即使服务程序可能是正常的。

  • 为3.13编写但使用3.14的客户端会遇到问题
  • 在以后版本中可能被修改。

重要的环境变量

1) EPICS_CA_ADDR_LIST

a.决定搜索哪里
b.是一个列表(由空格分隔)

如:"192.168.1.255 172.16.2.20 10.30.55.50"

c.默认是主机上所有网卡的广播地址

当服务器和客户端在相同子网时有效

d.广播地址
  • 发送给一个子网上所有服务器
  • 示例:192.168.1.255
  • 在UNIX上使用ifconfig -a查找它

2)  EPICS_CA_AUTO_ADDR_LIST

  • YES:在搜索中包含以上默认地址
  • NO:不要再默认地址上搜索
  • 如果你设置了EPICS_CA_ADDR_LIST, 通常设置这个为NO。

 其它重要的环境变量

1)CA客户端
  • EPICS_CA_ADDR_LIST
  • EPICS_CA_AUTO_ADDR_LIST
  • EPICS_CA_CONN_TMO
  • EPICS_CA_BEACON_PERIOD
  • EPICS_CA_REPEATER_PORT
  • EPICS_CA_SERVER_PORT
  • EPICS_CA_MAX_ARRAY_BYTES
  • EPICS_TS_MIN_WEST
2)CA服务器
  • EPICS_CAS_SERVER_PORT
  • EPICS_CAS_AUTO_BEACON_ADDR_LIST
  • EPICS_CAS_BEACON_PERIOD
  • EPICS_CAS_BEACON_PORT
  • EPICS_CAS_INFT_ADDR_LIST
  • EPICS_CAS_IGNORE_ADDR_LIST

3.13和3.14类似

  • 为了使为3.13编写的客户端在没有编码修改下对3.14有效,付出了非常大的努力
  • 甚至像MEDM的大型程序只需要进行少量的修改
  • 这表示已有程序一般不需要被重新编写。
  • 相比较,在切换到3.14中通道访问服务器需要很多更改

3.13和3.14不同

1) 3.14是线程的

你的程序不是必须是线程的。

2)3.14对某些功能有不同的名称。

  • ca_context_create对应ca_task_initialize
  • ca_context_destroy对应ca_task_exit
  • ca_create_channel对应ca_search_and_connect
  • ca_create_subscription对应ca_add_event
  • ca_clear_subscription对应ca_clear_event
  • 新函数可能有更多功能,通常与线程相关
  • 我们将使用新名称。

3)3.14对丢失连接有不同机制

  • 虚电路无响应(3.13中不可用)。
  • 虚电路断开

编写一个通道访问客户端的基本过程

1)初始化通道访问

ca_task_initialize或ca_context_create

2)搜索

ca_search_and_conntect或ca_create_channel

3)进行读或写

ca_get或ca_put

4)监视

ca_add_event或ca_create_subscription

5)让通道访问有机会运行

ca_poll, ca_pend_io, ca_pend_event

6)关闭通道访问

ca_task_exit或ca_context_destroy

所有C或C++程序必须包含cadef.h:#include <cadef.h>

库函数介绍

1)ca_context_create

enum ca_preemptive_callback_select{ca_disable_preemptive_callback,ca_enable_preemptive_callback
};int ca_context_create(enum ca_preemptive_callback_select SELECT);
  • 在任何其它调用前被调用一次
  • 设置通道访问
  • 除非你想要使用多线程,否则SELECT=ca_disable_preemptive_callback
  • 为了3.13兼容性,也可以使用ca_task_initialize()

2) ca_context_destroy

void ca_context_destroy()
  • 在退出你的程序前,应该被调用。
  • 关闭通道访问。
  • 为了3.13兼容性,也可以使用ca_task_exit()

3) ca_create_channel

typedef void caCh(struct connection_handler_args ARGS);
int ca_create_channel(const char * PVNAME,caCh * CALLBACK,void * PUSER,capri PRIORITY,chid * PCHID
);

a) 设置一个通道访问并且开始搜索过程。

b) PVNAME是过程变量的名称。

c) CALLBACK是你连接回调(或者NULL)

  • 当连接状态变化时,包括首次连接,将调用这个回调
  • 有关这个通道的消息被包含在ARGS中
  • 如果你不需要一个回调,使用NULL

d) PUSER是一种传递其它参数的方式

  • 你拥有的任何东西被存储在这个地址中
  • 它被存储在chid中
  • 在C++中,它经常是对应一个类的this指针
  • 如果你不需要它,使用NULL

e) 使用PRIORITY=CA_PRIORITY_DEFAULT

f) 一个chid是一个指向一个不透明struct的指针(地址),通道访问使用它存储有关这个通道大部分信息。chanId与chid相同(typdef chid chanId)

g) PCHID是chid指针的地址(使用&CHID)

  • 在进行调用前,你需要为chid分配空间
  • 通道访问将为这个struct分配空间并且返回它的地址

h) 使用宏访问chid中的信息

  • ca_name(CHID):获取这个过程变量的名称
  • ca_state(CHID):获取连接状态
  • ca_puser(CHID):获取你指定的PUSER

i) ARGS struct在连接回调中包含chid

j) 为了3.13兼容性也可以使用ca_search_and_connect()

4) ca_clear_channel

int ca_clear_channel(chid CHID);
  • 关闭一个通道访问并且回收资源。
  • 在退出这个程序前,应该被调用。
  • CHID与在ca_create_channel中使用相同的chid

5) ca_array_get

int ca_array_get(chtype TYPE,unsigned long COUNT,chid CHID,void * PVALUE
);

a) 从过程变量请求一个标量或者值的数组

b) 一般之后为ca_pend_io

c) TYPE是你变量的外部类型

  • 使用db_access.h中DBR_XXX类型之一
  • 例如:DBR_DOUBLE或DBR_STRING

d) COUNT:要读取的数组元素数目。

e) CHID:来自ca_create_channel的通道标识符。

f) PVALUE:你想要获取值存入的位置。必须有足够空间保存这些值。

6) ca_array_get_callback

typedef void (*pCallback)(struct event_handler_args ARGS);
int ca_array_get_callback(chtype TYPE,unsigned long COUNT,chid CHID,pCallback USERFUNC,void * USERARG
);

a) 使用一个回调,从一个过程变量请求一个标量或者值的数组。

b) TYPE:是你变量的外部类型。

  • 使用db_access.h中DBR_XXXX类型之一。
  • 例如:DBR_DOUBLE或DBR_STRING

c) COUNT:要读取的数组元素数目

d) CHID:是来自ca_create_channel的通道标识符。

e) USERFUNC:在操作结束时要被运行的你的回调的名称。

f) USERARGS:一种传递其它信息给这个回调的方式

  • struct event_handler_args有一个void * usr成员

7) ca_array_put

int ca_array_put(chtype TYPE,unsigned long COUNT,chid CHID,const void * PVALUE
);

a) 请求写一个标量或者值数组到一个过程变量

b) 一般之后为ca_pend_io

c) TYPE是你提供的外部类型

  • 使用db_access.h中DBR_XXXX类型之一
  • 例如:DBR_DOUBLE或DBR_STRING

d) COUNT是要写的数组元素的数目。

e) CHID是来自ca_create_channel的通道标识符。

f) PVALUE是从哪里寻找要被写的值。

8) ca_array_put_callback

typedef void (*pCallback)(struct event_handler_args ARGS);
int ca_array_put_callback(chtype TYPE,unsigned long COUNT,chid CHID,const void * PVALUE,pCallback USERFUNC,void * USERARG
);

a) 请求写一个标量或值数组到一个过程变量

b) TYPE是你变量的外部类型

  • 使用db_access.h中DBR_XXXX类型之一
  • 例如:DBR_DOUBLE或DBR_STRING

c) COUNT:要写的数组元素数目。

d)CHID:来自ca_create_channel的通道标识符。

e) PVALUE:查找要被写值的位置。

f) USERFUNC:当操作结束时,要被运行的你的回调的名称。

g) USERARG:一种传递其它信息给这个回调的方法。

  • struct event_handler_args有一个void * usr成员。

9) ca_create_subscription

typedef void (*pCallback)(struct event_handler_args ARGS);
int ca_create_subscriptino(chtype TYPE,unsigned long COUNT,chid CHID,unsigned long MASK,pCallback USERFUNC,void * USERARG,evid * PEVID
);

a) 指定一个回调函数,当这个过程变量经历显著状态变化时,被调用。

  • 值,警报状态,警报严重性
  • 这是监视一个过程变量的方法

b) TYPE是你想要返回的外部类型

  • 使用db_access.h中DBR_XXXX类型之一
  • 例如:DBR_DOUBLE或DBR_STRING

c) COUNT是要监视的数组元素数目

d) CHID是来自ca_create_channel的通道标识符。

e) MASK有对应于请求的事件触发类型的位集合

  • DBE_VALUE:值变化。
  • DBE_LOG:超过存档死区。
  • DBE_ALARM:警报状态变化

f) USERFUNC在状态变化发生时要被运行的你的回调的名称。

g) USERARG是一种传递其它信息给回调的方法。

  • struct event_handler_args有一个void *成员。

h) PEVID是一个evid(event id)的地址。

  • 在进行调用前你需要为evid分配空间
  • 类似chid
  • 仅用于清理订阅(如果不需要,可以是NULL)

10) ca_clear_subscription

int ca_clear_subscription(evid EVID);
  • 用于移除一个monitor回调
  • EVID是来自ca_create_subscription的evid

11)ca_add_exception_event

typedef void (* pCallback)(struct exception_handler_args ARGS);
int ca_add_exception_event(pCallback USERFUNC,void *USERARG
);

a)用于替代默认的exception处理程序。

b) USERFUNC是在一个异常发生时要被运行的你的回调的名称。

  • 使用NULL移除回调。

c) USERARG是一种传递其它信息给这个回调的方式。

  • struct exception_handler_args有一个void * usr成员

请求处理

1) 先前的例程是请求

  • 它们仅排队这个操作
  • 它们基本不出错。返回值基本总是ECA_NORMAL,但它们应该被检查。

2)仅在一下之一被调用时,这些请求才被处理。

  • ca_pend_io:在请求被处理前阻塞。
  • ca_pend_event:阻塞指定的时间。
  • ca_poll:仅处理当前工作。

3)如果这些例程没有被调用,请求不被处理并且后台任务也不被处理。

4)规则是这些之一应该每100ms被调用:允许后台任务运行(beacons等)。

1) ca_pend_io

int ca_pend_io(double TIMEOUT);

a)清空发送缓存。

b) 在以下发生前,最多阻塞TIMEOUT秒 

  • 待处理gets结束
  • 没有回调已经连接的搜索

c) 当gets和搜索结束时,返回ECA_NORMAL

d)返回ECA_TIMEOUT,否则

  • 表示某过程出错
  • get请求可以被再次发出
  • 在ca_clear_channel后,搜索请求可以被再次发出。

e) 通道访问后台任务被执行

  • 除非没有待处理的I/O请求

f) 与不使用回调的搜索,gets和puts一起使用。

2) ca_pend_event

int ca_pend_event(double TIMEOUT);

a) 清空发送缓存。

b) 在TIMEOUT秒内运行后台任务。

  • 在TIMEOUT秒耗尽时才返回。

c) 当你的程序不是必须做任何其它事情时使用这个函数。

d) 使用ca_pend_event替代sleep

3) ca_poll

int ca_poll();

a) 清空发送缓存。

b) 仅运行待处理任务。

  • 当没有待处理任务时退出,否则类似于ca_pend_event

c) 当你的程序有要做的其它事情时,使用这个函数。

  • 例如:大多数GUI程序。

d)确认它至少每100ms被调用。

4) CHID宏

chtype ca_field_type(CHID);
unsigned ca_element_count(CHID);
char * ca_name(CHID);
void * ca_puser(CHID);
void ca_set_puser(chid CHID, void * puser);
enum channel_state{cs_never_conn, //有效chid,服务器未找到或者不可用cs_prev_conn,  //有效chid,先前连接到服务器cs_conn,       //有效chid,连接了服务器cs_closed      //用户删除了通道
};
char * ca_host_name(CHID);
char * ca_read_access(CHID);
char * ca_write_access(CHID)

5) ca_connection_handler_args

struct ca_connection_handler_args{chidId chid; // 通道idlong op;     // CA_OP_CONN_UP/CA_OP_CONN_DOWN
};
  • 在连接回调中使用
  • 注意:使用了chanId而不是chid,某些编译器不认chid chid
  •  

6) event_handler_args

typedef struct event_handler_args{void * usr;  // 提供给请求的用户参数chanId chid;  //通道IDlong type;  //返回项的类型long count;   //返回项的元素数目const void * dbr; //指向返回项的指针int status;       //请求op的ECA_XXX状态
};
  • 在get, put和monitor回调中使用
  • 如果status不是ECA_NORMAL,不要使用dbr中的值。

7) 通道访问API函数

 

简单的CA客户端

1) 使用以下数据库文件,此数据库文件由两个记录组成一个wavefrom记录和一个stringin记录。

record(waveform, "$(USER):wfin") {field(DESC, "A Example Waveform")field(SCAN, "Passive")field(NELM, "10")field(FTVL, "LONG")
}record(stringin, "$(USER):StrIn") {field(DESC, "A Example StringIn")field(SCAN, "Passive")field(VAL, "HelloWorld")field(PINI, "YES")
}

2)将以上数据库加载到一个IOC中产生一个两个记录实例:

epics> dbl
TEST:StrIn
TEST:wfin

3) 用EPICS base自带的通道访问命令测试以上两个记录:

orangepi@orangepi4-lts:~/host_program/host/hostApp$ caget TEST:StrIn
TEST:StrIn                     HelloEveryOne
orangepi@orangepi4-lts:~/host_program/host/hostApp$ caget TEST:wfin
TEST:wfin 10 1 2 3 4 5 6 7 8 9 10

4) 用以上讲解的通道访问API函数写一个自己的通道访问程序,源代码如下:

orangepi@orangepi4-lts:~/host_program/host/hostApp$ cat simpleget.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>/* EPICS header */
#include "cadef.h"
#define epicsAlarmGLOBAL
#include "epicsEvent.h"
#include "epicsMutex.h"#define TIMEOUT         1.0
#define SCA_OK          1
#define SCA_ERR         0
#define MAX_STRING      40int main(int argc, char **argv)
{int stat;chid pCh;char pvname[20] = {0};char svalue[100];int  ivalue[20];void * pvalue;if (argc != 2){printf("Usage: %s channelname\n", argv[0]);exit(1);}strcpy(pvname, argv[1]);printf("PVNAME: %s\n", pvname);/* Initialize channel access */stat = ca_context_create(ca_disable_preemptive_callback);if (stat != ECA_NORMAL){printf("ca_context_create failed:\n%s\n",ca_message(stat));exit(1);}else{printf("channel accesss initialized successfully\n");}/* create the pv */stat = ca_create_channel(pvname, NULL, NULL, CA_PRIORITY_DEFAULT, &pCh);if (stat != ECA_NORMAL){printf("ca_create_channel failed:\n%s\n", ca_message(stat));goto EXIT;}else{printf("PV for channel name %s created successfully\n", pvname);}/* call ca_pend_io to process the search */stat = ca_pend_io(TIMEOUT);if (stat != ECA_NORMAL){printf("search for PV:[%s] timed out after %g sec", pvname, TIMEOUT);goto DESTROY;}/* Macro TEST */printf("MACRO TEST:\n");int request_type = ca_field_type(pCh);printf("ca_field_type(CHID): %d\n", request_type);long request_count = ca_element_count(pCh);printf("ca_element_count(CHID): %ld\n", request_count);printf("ca_name(CHID):%s\n", ca_name(pCh));printf("ca_state(CHID): %d\n", ca_state(pCh));printf("ca_host_name(CHID):%s\n",ca_host_name(pCh));printf("ca_read_access(CHID):%d\n", ca_read_access(pCh));printf("ca_write_access(CHID):%d\n", ca_write_access(pCh));printf("DBR_STRING: %d\n", DBR_STRING);printf("DBR_LONG: %d\n", DBR_LONG);/* Request Get */if (request_type == DBR_STRING){pvalue = svalue;}else if(request_type == DBR_LONG){pvalue = ivalue;}else{printf("NO SUPPORT TYPE: %d\n", request_type);goto DESTROY;}/* Request the get */stat = ca_array_get(request_type, request_count, pCh, pvalue);if (stat != ECA_NORMAL){printf("ca_array_get failed:\n%s\n", ca_message(stat));goto DESTROY;}/* call ca_pend_io to get the values */stat = ca_pend_io(TIMEOUT);if (stat != ECA_NORMAL){printf("get %s timed out after %g sec\n%s\n", pvname, TIMEOUT, ca_message(stat));goto DESTROY;}if (request_type == DBR_STRING){printf("PV[%s] ===> VAlUE[%s]\n", pvname, svalue);}else if (request_type == DBR_LONG){int i, ret = 0;for (i = 0; i < request_count; i++){ret += sprintf(svalue + ret, "%d ", ivalue[i]);}printf("PV[%s] ==> VALUE[%s]\n", pvname, svalue);}DESTROY:stat = ca_clear_channel(pCh);if (stat != ECA_NORMAL){printf("ca_clear_channel failed [%s] \n%s\n",pvname,ca_message(stat));goto EXIT;}/* clean up channel */
EXIT:   ca_context_destroy();printf("channel access context destroyed and exits the program\n");return 0;
}

编译以上程序代码,并且对以上记录执行,结果如下:

orangepi@orangepi4-lts:~/host_program/host/hostApp$ O.linux-aarch64/simpleget TEST:StrIn
PVNAME: TEST:StrIn
channel accesss initialized successfully
PV for channel name TEST:StrIn created successfully
MACRO TEST:
ca_field_type(CHID): 0
ca_element_count(CHID): 1
ca_name(CHID):TEST:StrIn
ca_state(CHID): 2
ca_host_name(CHID):192.168.50.184:5064
ca_read_access(CHID):1
ca_write_access(CHID):1
DBR_STRING: 0
DBR_LONG: 5
PV[TEST:StrIn] ===> VAlUE[HelloEveryOne]
channel access context destroyed and exits the program
orangepi@orangepi4-lts:~/host_program/host/hostApp$ O.linux-aarch64/simpleget TEST:wfin
PVNAME: TEST:wfin
channel accesss initialized successfully
PV for channel name TEST:wfin created successfully
MACRO TEST:
ca_field_type(CHID): 5
ca_element_count(CHID): 10
ca_name(CHID):TEST:wfin
ca_state(CHID): 2
ca_host_name(CHID):192.168.50.184:5064
ca_read_access(CHID):1
ca_write_access(CHID):1
DBR_STRING: 0
DBR_LONG: 5
PV[TEST:wfin] ==> VALUE[1 2 3 4 5 6 7 8 9 10 ]
channel access context destroyed and exits the program

通过以上实例程序编写和测试,可以进一步加强我们对EPICS通道访问函数的理解。


http://www.mrgr.cn/p/51013717

相关文章

Linux标准库API

目录 1.字符串函数 2.数据转换函数 3.格式化输入输出函数 4.权限控制函数 5.IO函数 6.进程控制函数 7.文件和目录函数 1.字符串函数 2.数据转换函数 3.格式化输入输出函数 #include<stdarg.h>void test(const char * format , ...){va_list ap;va_start(ap,format…

IntelliJ IDEA流行的构建工具——Gradle

IntelliJ IDEA&#xff0c;是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超常的。 如…

【Docker】Docker应用部署之Docekr容器安装Nginx

目录 一、搜索镜像 二、拉取镜像 三、创建容器 四、测试使用 一、搜索镜像 docker search nginx 二、拉取镜像 docker pull nginx # 不加冒号版本号 默认拉取最新版 三、创建容器 首先我们需要在宿主机创建数据卷目录 mkdir nginx # 创建目录 cd nginx # 进入目录 mkd…

React 路由使用-详细介绍

路由初使用 抽象路由模块 src\page\Article\index.js const Article () > {return (<div><p>文章页</p></div>); };export default Article;src\router\index.js // 导入页面 import Article from "../page/Article"; import Login fr…

安全学习DAY08_算法加密

算法加密 漏洞分析、漏洞勘测、漏洞探针、挖漏洞时要用到的技术知识 存储密码加密-应用对象传输加密编码-发送回显数据传输格式-统一格式代码特性混淆-开发语言 传输数据 – 加密型&编码型 安全测试时&#xff0c;通常会进行数据的修改增加提交测试 数据在传输的时候进行…

CAN转EtherNet/IP网关can协议破解服务

JM-EIP-CAN 是自主研发的一款 ETHERNET/IP 从站功能的通讯网关。该产品主要功能是将各种 CAN 总线和 ETHERNET/IP 网络连接起来。 本网关连接到 ETHERNET/IP 总线中做为从站使用&#xff0c;连接到 CAN 总线中根据节点号进行读写。 技术参数 ETHERNET/IP 技术参数 网关做为 …

怎么把PDF转为word?1分钟解决难题

PDF文件在我们的电脑上应用非常广泛&#xff0c;由于其较高的安全性和兼容性&#xff0c;得到了广泛的认可。然而&#xff0c;对于一些人来说&#xff0c;PDF文件不能直接进行编辑和修改可能是一个问题。因此&#xff0c;通常我们需要将其转换为Word格式&#xff0c;以便在Word…

C++——STL容器之list链表的讲解

目录 一.list的介绍 二.list类成员函数的讲解 2.2迭代器 三.添加删除数据&#xff1a; 3.1添加&#xff1a; 3.2删除数据 四.排序及去重函数&#xff1a; 错误案例如下&#xff1a; 方法如下&#xff1a; 一.list的介绍 list列表是序列容器&#xff0c;允许在序列内的任何…

记一次 .NET 某物流API系统 CPU爆高分析

一&#xff1a;背景 1. 讲故事 前段时间有位朋友找到我&#xff0c;说他程序CPU直接被打满了&#xff0c;让我帮忙看下怎么回事&#xff0c;截图如下&#xff1a; 看了下是两个相同的程序&#xff0c;既然被打满了那就抓一个 dump 看看到底咋回事。 二&#xff1a;为什么会打…

团队任务管理器工具推荐:三款适合协作工作的首选

如果您是项目经理或领导一个小团队&#xff0c;那么每天要完成的任务列表似乎无穷无尽。对于任何规模的公司来说&#xff0c;在不依赖任何软件的情况下掌握任务管理的不同方面都是一项挑战。满足您项目管理需求的正确软件可以显著提高团队的生产力——无论您的团队规模或项目范…

uni-app在小米手机上运行【步骤细节】

注意细节重点&#xff1a; 1.手机使用数据线与电脑连接&#xff0c;手机连接模式必须是传输文件模式 2.手机必须打开开发者模式 3.打开开发者模式后&#xff0c;仔细浏览并调整USB调试权限&#xff0c;重点打开USB是否允许安装按钮&#xff01;&#xff01;&#xff01; 操作步…

大家做性能测试都用什么工具

在进行测试时&#xff0c;选择适合的测试工具至关重要&#xff0c;因为优秀的测试工具能够显著提高工作效率。对于性能测试和自动化测试而言&#xff0c;大多数人会选择传统的JMeter等工具&#xff0c;然而这些工具存在学习成本高、使用门槛高的问题。 因此&#xff0c;我在这…

MFC表格控件CListCtrl的改造及用法

1、目的 简单描述MFC的表格控件使用方法。Qt适用习惯了以后MFC用的比较别扭&#xff0c;因此记录一下以备后续复制代码使用。由于MFC原生的CListCtrl比较局限&#xff0c;比如无法改变表格的背景色、文字颜色等设定&#xff0c;因此先对CListCtrl类进行重写&#xff0c;以便满足…

8.事件对象

8.1获取事件对象 ●事件对象是什么 也是个对象&#xff0c;这个对象里有事件触发时的相关信息 例如&#xff1a;鼠标点击事件中&#xff0c;事件对象就存了鼠标点在哪个位置等信息 ●使用场景 可以判断用户按下哪个键&#xff0c;比如按下回车键可以发布新闻 可以判断鼠标点击…

python与深度学习(八):CNN和fashion_mnist二

目录 1. 说明2. fashion_mnist的CNN模型测试2.1 导入相关库2.2 加载数据和模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章训练的模型进行测…

springboot整合myabtis+mysql

一、pom.xml <!--mysql驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--springboot与JDBC整合包--><dependency><groupId>org.springframework.b…

第十章:重新审视扩张卷积:一种用于弱监督和半监督语义分割的简单方法

0.摘要 尽管取得了显著的进展&#xff0c;弱监督分割方法仍然不如完全监督方法。我们观察到性能差距主要来自于它们在从图像级别监督中学习生成高质量的密集目标定位图的能力有限。为了缓解这样的差距&#xff0c;我们重新审视了扩张卷积[1]并揭示了它如何以一种新颖的方式被用…

开源视频监控管理平台国标GB28181视频EasyCVR电子地图功能展示优化

视频汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频监控综合管理平台EasyCVR可提供的视频能力包括&#…

ssh安全远程管理

目录 1、什么是ssh 2、ssh登陆 3、ssh文件传输 1、什么是ssh ssh是 Secure Shell 的缩写&#xff0c;是一个建立在应用层上的安全远程管理协议。ssh 是目前较为可靠的传输协议&#xff0c;专为远程登录会话和其他网络服务提供安全性。利用ssh 协议可以有效防止远程管理过程中…

macos下安装john the ripper并配置zip2john+破解加密zip文件

为了破解加密的zip文件&#xff0c;需要用到john进行爆破密码。 1、首先使用homebrew安装john&#xff0c;可以安装它的增强版john-jumbo: brew install john-jumbo 2、安装后可以使用 john 命令验证&#xff1a; john 3、配置zip2john的环境——.zshrc下&#xff0c;&#x…