Ubuntu 22.04上/etc/init.d/softIOC脚本解析

如何在Linux上设立一个软IOC框架

以下说明是基于我们的Debian Linux机器。其它发行版(或其他Unixes)会有不同命令和对于东西有不同位置。这对我添加到本页的Debian /etc/init.d尤其如此。如果你为一个不同发行版创建一个不同的脚本,请添加它到本页。其它人将能够使用它。但基本步骤在所有发行版上相同。我已经认为了解了基本的系统管理任务(创建用户账户等)。

介绍

我们为什么做这件事?

当在生产中使用软IOC时,它们应该被当作重要的系统服务:

  1. 软IOCs应该由系统启动和停止。
  2. 应该有后备系统,遇到硬件故障,你可以简单地切换到这个后备系统。

其它目标是:用如用于VME IOCs相同地方法,应用程序开发这应该能够在无需对主机进行root访问下重置软IOC。

  • IOC应用开发者应该能够手动启动和停止IOCs。

当多个软IOC共享相同主机(和相同IP地址)时,通道访问不能区分它们。访问安全将不能区分来自不同软IOCs的CA连接。在调试客户端时,CA不能告诉你一个连接去向哪个软IOCs。

  • 即使不同软IOCs驻留在相同机器上,通道访问应该能够区分不同的软IOCs。

我曾考虑使用一个虚拟化层(基于VMware)在一个封装环境中运行软IOCs。我发现工作量太高,此层太厚,并且预计的性能损失太大--仅得到了每个软IOIC一个单独IP地址。

在调试和/或尝试查看在一个IOC上发生了什么时,开发者不必要知道数据库运行在一个基于VME上还是在一个基于主机的软IOC上。

  • Console访问(以及记录console输出日志)应该是统一的:对于软IOCs和VME IOCs使用相同方式。

实现这个目标所需的设置在文档<<如何为VME和软IOCs设置Console访问和日志>>。

概念

要使访问安全区分软IOCs,在不同用户名下运行它们。

procServ工具将用做一个环境,它允许在后台启动软IOCs并且之后连接到它们的consoles,非常类型VME IOCs的串行consoles。(见EPICS Related Software — EPICS Documentation documentation (epics-controls.org)上procServ链接。之前,使用screen工具,但报告的问题,例如,在console访问后IOCs挂起,使得我们切花到复杂性更低的东西)。

/etc/init.d/softIOC是用于将EPICS软IOC作为系统服务启动的脚本:参考网页https://wiki-ext.aps.anl.gov/epics/index.php/How_to_Set_Up_a_Soft_IOC_Framework_on_Linux

这个脚本的描述:

DESC="EPICS soft IOCs"

这个脚本的完整路径:

SCRIPTNAME=/etc/init.d/softIOC

获取主机名称:

HOST=`uname -n`

 设置procServ程序的路径

PROCSERV=/usr/bin/procServ

设置配置文件的完整路径: 

CONFFILE=/usr/local/EPICS/program/softIOC/softiocs.orangepi5plus

设置IOC应用程序所在的家目录: 

HOMEDIRS=/usr/local/EPICS/program

检查配置文件 , 不能读取配置文件,显示不能找到配置文件,并且以错误码1退出本脚本。

if [ ! -r $CONFFILE ]
thenecho "Error: Can't find configuration file $CONFFILE!"exit 1
fi

 此函数函数:清理环境变量"CA_AUTO" "CA_ADDR" "CA_PORT" "IOC_USER" "PORT"。

clear_options()
{for option in "CA_AUTO" "CA_ADDR" "CA_PORT" "IOC_USER" "PORT"dounset $option;done
}

clear_options()的测试脚本如下:

echo "=============test clear_options() ====================="
export CA_AUTO="NO"
export CA_ADDR="127.0.0.1"
export CA_PORT=5065
export IOC_USER="blctrl"
export PORT="20000"
echo "CA_AUTO=$CA_AUTO"
echo "CA_ADDR=$CA_ADDR"
echo "CA_PORT=$CA_PORT"
echo "IOC_USER=$IOC_USER"
echo "PORT=$PORT"
echo "call clear_options()"
clear_options
echo "called clear_options()"
echo "CA_AUTO=$CA_AUTO"
echo "CA_ADDR=$CA_ADDR"
echo "CA_PORT=$CA_PORT"
echo "IOC_USER=$IOC_USER"
echo "PORT=$PORT"
echo "===================end================================="
echo ""

测试结果:

=============test clear_options() =====================
CA_AUTO=NO
CA_ADDR=127.0.0.1
CA_PORT=5065
IOC_USER=blctrl
PORT=20000
call clear_options()
called clear_options()
CA_AUTO=
CA_ADDR=
CA_PORT=
IOC_USER=
PORT=
===================end=================================

根据读入参数设置环境变量:

evaluate_options()
{while [ $# != 0 ]do      # 将第一个参数的小写字符全部替换成大写字母TAG=`echo $1 | tr [:lower:] [:upper:]`case "$TAG" in"#")            ;; # 匹配”#”,则进入下次循环"CA_AUTO" | "CA_ADDR" | "CA_PORT" | "COREDUMPSIZE" | \"HOMEDIR" | "BOOTDIR" | "IOC_USER" | "PORT" ) # 匹配这些字符# 测试当前选项值的存在OPTION=$TAGshiftif [ -z $TAG -o $TAG = "#" ] # TAG变量为空或者内容为”#”thenecho "$CONFFILE: Value(s) required for $TAG.";exit 1elseVALUE=$1shiftfi# 如果多个值跟随,也分配它们while [ $1 != '#'  -a  $# != 0 ]doVALUE="$VALUE $1"shift;doneeval ${OPTION}=\$VALUE;;*)              echo "$CONFFILE: Unknown option $1."exit 1esacshiftdone
}

测试evaluate_options()函数的脚本:

echo "============================Test evaluate_options============================="
ARGS="CA_AUTO NO # CA_ADDR 127.0.0.1 # CA_PORT 5065 5066 # IOC_USER blctrl # PORT 20000"
evaluate_options ${ARGS}
echo CA_AUTO=$CA_AUTO
echo CA_ADDR=$CA_ADDR
echo CA_PORT=$CA_PORT
echo IOC_USER=$IOC_USER
echo PORT=$PORT
echo "============================Test evaluate_options==============================="

测试结果如下:

============================Test evaluate_options=============================
CA_AUTO=NO
CA_ADDR=127.0.0.1
CA_PORT=5065 5066
IOC_USER=blctrl
PORT=20000
============================Test evaluate_options===============================

  为选项设置IOC环境变量默认值可能在配置文件中被重写:

  • BOOTDIR:IOC启动目录。
  • HOMEDIR:IOC应用程序顶层目录
  • PIDFILE:生产的pid文件路径
  • ENVFILE:环境文件路径
  • IOC_USER:IOC应用程序的用户
default_options()
{IOC_LC=$1BOOTDIR=$HOMEDIRS/$LOC_LC/iocBoot/ioc$LOC_LC/HOMEDIR=$HOMEDIRS/$IOC_LCPIDFILE=$HOMEDIR/$IOC_LC.pidENVFILE=$HOMEDIR/$IOC_LC.envIOC_USER=blctrl
}

default_options()的测试脚本如下:

#echo "===================Test default_options()=============="
default_options "aiDriver"
echo "BOOTDIR=$BOOTDIR"
echo "HOMEDIRS=$HOMEDIRS"
echo "HOMEDIR=$HOMEDIR"
echo "PIDFILE=$PIDFILE"
echo "IOC_USER=blctrl"
#echo "===================end================================="
#echo ""

测试结果如下:

BOOTDIR=/usr/local/EPICS/program/aiDriver/iocBoot/iocaiDriver/
HOMEDIRS=/usr/local/EPICS/program
HOMEDIR=/usr/local/EPICS/program/aiDriver
PIDFILE=/usr/local/EPICS/program/aiDriver/aiDriver.pid
IOC_USER=blctrl

从配置文件中读取配置信息,并且生产一个如以下格式的 

assign_options()
{TAG=$1SECTION=`sed -n "/^$TAG:/I,/^[\t ]*$/p" $CONFFILE | \      # 查找$TAG段落sed -n '/^[^#]/p' | \                             # 删除注释 sed -e 's/^[ \t]*//' -e 's/[ \t]*$//' \           # 删除开头和结尾空白-e "s/$TAG://I" \                             # 移除$TAG:标签-e :a -e '/\\\\$/N; s/\\\\\\n//; ta' \        # 将以一个”\”结尾的行合并-e 's/$/ \#/' \                               # 用一个”#”标记选项结尾-e 's/[\t ]/ /g'`                             #移除不必要的空白evaluate_options $SECTION
}

assign_options的测试脚本如下:

echo "=================Test assign_options()================="
assign_options aiDriver
echo SECTION=$SECTION
echo PORT=$PORT
echo CA_AUTO=$CA_AUTO
echo CA_ADDR =$CA_ADDR
echo CA_PORT =$CA_PORT
echo IOC_USER =$IOC_USER
echo "===================end================================="
echo ""

配置文件所在完整路径/usr/local/EPICS/program/softIOC/softiocs.orangepi5plus:

AUTO:   aiDriverGLOBAL:aiDriver:
# 配置端口号
PORT 20000
CA_AUTO NO
CA_ADDR 192.168.50.10
CA_PORT 5080
IOC_USER blctrl
PORT 20000

测试结果如下:

=================Test assign_options()=================
SECTION= # PORT 20000 # CA_AUTO NO # CA_ADDR 192.168.50.10 # CA_PORT 5080 # IOC_USER blctrl # PORT 20000 #
PORT=20000
CA_AUTO=NO
CA_ADDR =192.168.50.10
CA_PORT =5080
IOC_USER =blctrl

从命令行或配置文件中AUTO:项获取IOCs。测试配置文件中的匹配段落。

get_iocs()
{if [ $# = 0 ]thenTEST_LIST=`grep -i '^AUTO:' "$CONFFILE" | cut -d: -f2-`elseTEST_LIST="$@"fiCHECKED_LIST=""for IOC in $TEST_LISTdogrep -qi "^$IOC:" $CONFFILEif [ $? = 0 ]thenCHECKED_LIST="$CHECKED_LIST $IOC"fidoneecho $CHECKED_LIST
}

get_iocs()的测试脚本如下: 

echo "===============Test get_iocs()========================="
echo "call get_iocs"
get_iocs
echo "call get_iocs aiDriver"
get_iocs aiDriver
echo "===================end================================="
echo ""

测试结果如下:

===============Test get_iocs()=========================
call get_iocs
aiDriver
call get_iocs aiDriver
aiDriver
===================end=================================

 此脚本第一方面设置环境变量设置字符串,例如CA_AUTO环变量不为空,则将其设置到环境变量,其它CA_XXX环境变量的设置类似,第二方面为procserv程序设置选项。

set_cmdenvopts()
{EPICS_CA_AUTO_ADDR_LIST中,并且进行导出SETENV="LINES=60 "`test ! -z "$CA_AUTO" && echo "export EPICS_CA_AUTO_ADDR_LIST=\"$CA_AUTO\";"`SETENV="$SETENV "`test ! -z "$CA_ADDR" && echo "export EPICS_CA_ADDR_LIST=\"$CA_ADDR\";"`SETENV="$SETENV "`test ! -z "$CA_PORT" && echo "export EPICS_CA_SERVER_PORT=\"$CA_PORT\";"`SETENV="$SETENV "`test ! -z "$BOOTDIR" && echo "export BOOTDIR=\"$BOOTDIR\";"`PROCSERVOPTS=`test ! -z "$IOC_USER" && echo "-n \"$IOC_USER\""`PROCSERVOPTS="$PROCSERVOPTS "`test ! -z "$COREDUMPSIZE" && echo "--coresize \"$COREDUMPSIZE\""`PROCSERVOPTS="$PROCSERVOPTS -q -c $BOOTDIR -p $PIDFILE -i ^D^C^] $PORT"
}

set_cmdenvpots()的测试脚本如下:

echo "================Test set_cmdenvopts()=================="
default_options aiDriver
assign_options aiDriver
set_cmdenvoptsecho "SETENV=$SETENV"
echo "PROCSERVOPTS=$PROCSERVOPTS"echo "===================end================================="
echo ""

测试结果如下:

SETENV变量内容可以设置以下变量:

  • LINES=60
  • export EPICS_CA_AUTO_ADDR_LIST="NO"
  • export EPICS_CA_ADDR_LIST="127.0.0.1"
  • export EPICS_CA_SERVER_PORT="5080";
  • export BOOTDIR="/usr/local/EPICS/program/aiDriver/iocBoot/iocaiDriver/"

PROCSERVPORTS内容可以设置procserv的选项:

  • -n "blctrl"  :在所有服务程序消息中,使用blctrl替代完整命令行来增加可读性。
  • -q:不要写信息输出(服务程序)。当作为系统脚本的一部分运行时,避免弄乱屏幕。
  • -c /usr/local/EPICS/program/aiDriver/iocBoot/iocaiDriver/:在启动子进程前,切换目录为 /usr/local/EPICS/program/aiDriver/iocBoot/iocaiDriver/。
  • -p /usr/local/EPICS/program/aiDriver/aiDriver.pid:写服务进程的PID到file以便于集成到常规的系统服务管理机制中。
  • -i ^D^C^]:忽略访问连接上再chars中所有字符。
  • 20000:本地ftp连接端口。
================Test set_cmdenvopts()==================
SETENV=LINES=60 export EPICS_CA_AUTO_ADDR_LIST="NO"; export EPICS_CA_ADDR_LIST="127.0.0.1"; export EPICS_CA_SERVER_PORT="5080"; export BOOTDIR="/usr/local/EPICS/program/aiDriver/iocBoot/iocaiDriver/";
PROCSERVOPTS=-n "blctrl"  -q -c /usr/local/EPICS/program/aiDriver/iocBoot/iocaiDriver/ -p /usr/local/EPICS/program/aiDriver/aiDriver.pid -i ^D^C^] 20000
===================end=================================

启动守护/服务进程的函数: 

do_start()
{# 返回#   0:启动了守护进程 #   1:守护进程已经在运行 #   2:不能启动守护进程 # 如果需要,在此处添加代码,其等待这个进程准备好处理来自之后启动的服务的请求,这个服务依赖于这个进程。作为最后的方法,休眠一段时间。echo -n "Starting soft IOCs ... "MYIOCS=`get_iocs $@`[ "$MYIOCS" = "" ] && echo -n "<none> "for IOC in $MYIOCSdoecho -n "$IOC "clear_options           #清除环境变量default_options "$IOC"  #设置默认环境变量assign_options "GLOBAL" #设置全局设置的环境变量assign_options "$IOC"   #设置本IOC的环境变量set_cmdenvopts          #用于启动IOC的环境变量字符串,用于procserv的选项字符串if [ -d $BOOTDIR ]     # 测试启动目录是否存在thenif [ -d $HOMEDIR ] # 测试家目录是否存在then# 测试是否已经有pidfile文件$PIDFILE的进程在运行了,如果是返回1sudo -H -u $IOC_USER bash -c "$SETENV (env > $ENVFILE; /usr/sbin/start-stop-daemon --start --quiet --chdir $BOOTDIR \--pidfile $PIDFILE --startas $PROCSERV --name procServ --test > /dev/null)"if [ "$?" = 1 ]thenecho -n "<was running> "else# 启动服务进程以及IOCsudo -H -u $IOC_USER bash -c "$SETENV (env > $ENVFILE; /usr/sbin/start-stop-daemon --start --quiet --chdir $BOOTDIR \--pidfile $PIDFILE --startas $PROCSERV --name procServ -- $PROCSERVOPTS ./st.cmd)"if [ "$?" = 1 ]thenecho -n "<failed> "fifielseecho -e "\nWarning: Home directory $HOMEDIR does not exist! Ignoring $IOC"fielseecho -e "\nWarning: Boot directory $BOOTDIR does not exist! Ignoring $IOC"fidoneecho "... done."
}

do_start的测试脚本如下:

echo "========================Test do_start()============================="
default_options aiDriver
assign_options aiDriver
set_cmdenvoptsdo_start aiDriver
echo "===================end================================="
echo ""

测试结果如下:

========================Test do_start()=============================
Starting soft IOCs ... aiDriver ... done.
===================end=================================

IOC顶层目录下,产生两个新的文件aiDriver.env和aiDriver.pid:

:/usr/local/EPICS/program/aiDriver# ls
aiDriverApp  aiDriver.env  aiDriver.pid  bin  configure  db  dbd  iocBoot  lib  Makefile

ftp本地连接20000端口,进行测试:

root@orangepi5plus:~# telnet localhost 20000
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
@@@ Welcome to procServ (procServ Process Server 2.7.0)
@@@ Use ^X to kill the child, auto restart is ON, use ^T to toggle auto restart
@@@ procServ server PID: 171785
@@@ Server startup directory: /usr/local/EPICS/program/aiDriver/iocBoot/iocaiDriver
@@@ Child startup directory: /usr/local/EPICS/program/aiDriver/iocBoot/iocaiDriver/
@@@ Child "orangepi" started as: ./st.cmd
@@@ Child "orangepi" PID: 171786
@@@ procServ server started at: Fri Jul  5 15:11:02 2024
@@@ Child "orangepi" started at: Fri Jul  5 15:11:02 2024
@@@ 0 user(s) and 0 logger(s) connected (plus you)epics> dbl
Random:AiRandom

通道访问这个IOC:

caget Random:AiRandom
Random:AiRandom                527

停止守护/服务进程的函数:

sudo -H -u $IOC_USER bash -c "/usr/sbin/start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name procServ"

--retry:使用--stop,指定start-stop-daemon检查这些进程是否结束了。它将重复检查任何匹配的进行是否正在运行,直到没有匹配的进程运行。如果这些进程不存在,它将采取由调度表决定的进一步操作。如果指定了timeout替代schedule,则调度表signal/timeout/KILL/timeout被使用,此处signal是由--signal指定的信号。

schedule是一个列表,其至少有由斜杆(/)分隔的两项;每项可能是-signal-number或[-]signal-name,它表示发送那个信号,或timeout,它表示为进程退出等待那些秒数,或者forever,它表示如果需要一直重复调度表余下的。

do_stop()
{# 返回:#   0:守护进程被停止#   1:守护进程已经停止#   2:守护进程不能被停止#   3:发生故障echo -n "Stopping soft IOCs ... "MYIOCS=`get_iocs $@`[ "$MYIOCS" = "" ] && echo -n "<none> "for IOC in $MYIOCSdoecho -n "$IOC "clear_optionsdefault_options "$IOC"assign_options "GLOBAL"assign_options "$IOC"set_cmdenvopts# 测试停止守护进程, 返回1,表示已经停止sudo -H -u $IOC_USER bash -c "/usr/sbin/start-stop-daemon --stop --quiet --pidfile $PIDFILE --name procServ --test > /dev/null"if [ $? = 1 ]thenecho -n "<not running> "elsesudo -H -u $IOC_USER bash -c "/usr/sbin/start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name procServ"if [ $? = 1 ]thenecho -n "<failed> "elsesudo -H -u $IOC_USER bash -c "rm -f $PIDFILE"fifidoneecho "... done."
}

do_stop的测试脚本:

echo "========================Test do_start()============================="
default_options aiDriver
assign_options aiDriver
set_cmdenvoptsdo_stop aiDriver
echo "===================end================================="
echo ""

测试结果如下,ftp服务程序和epics ioc程序都已经终止。

========================Test do_start()=============================
Stopping soft IOCs ... aiDriver ... done.
===================end=================================root@orangepi5plus:~# ss -tlnp
State      Recv-Q     Send-Q          Local Address:Port           Peer Address:Port     Process
LISTEN     0          128                   0.0.0.0:22                  0.0.0.0:*         users:(("sshd",pid=1383,fd=3))
LISTEN     0          4                   127.0.0.1:5037                0.0.0.0:*         users:(("adbd",pid=849,fd=5))
LISTEN     0          4096                  0.0.0.0:111                 0.0.0.0:*         users:(("rpcbind",pid=900,fd=4),("systemd",pid=1,fd=32))
LISTEN     0          4                     0.0.0.0:5555                0.0.0.0:*         users:(("adbd",pid=849,fd=10))
LISTEN     0          4096            127.0.0.53%lo:53                  0.0.0.0:*         users:(("systemd-resolve",pid=901,fd=14))
LISTEN     0          128                      [::]:22                     [::]:*         users:(("sshd",pid=1383,fd=4))
LISTEN     0          4096                     [::]:111                    [::]:*         users:(("rpcbind",pid=900,fd=6),("systemd",pid=1,fd=34))

并且IOC顶层目录中pidfile文件也被删除了:

root@orangepi5plus:/usr/local/EPICS/program/aiDriver# ls
aiDriverApp  aiDriver.env  bin  configure  db  dbd  iocBoot  lib  Makefile

发送SIGHUP信号给守护/服务进程的函数如下(此处没有实现):

do_reload() {# 如果守护进程可以在不重启下重载其配置(例如,当向其发送要给SIGHUP),# 则在此实现。#       start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
#       return 0echo "Restarting soft IOCs ... "STARTDIR=$PWDIOCS=`get_iocs $@`[ "$IOCS" = "" ] && echo -n "<none> "for IOC in $IOCSdoecho -n "$IOC "clear_optionsdefault_options "$IOC"assign_options "GLOBAL"assign_options "$IOC"if [ -d $BOOTDIR ]thencd "$BOOTDIR"
# restart it!echo -e "\ndebug: Reloading ioc $IOC"cd "$STARTDIR"elseecho -e "\nWarning: Boot directory $BOOTDIR does not exist! Entry for $NET ignored!"fidoneecho "... done."
}

以下脚本用于从命令 行获取参数,并且执行守护进程启动/停止/重启:

COMMAND=$1
shift
IOCS=`echo $@`case "$COMMAND" instart)do_start $IOCS;;stop)do_stop $IOCS;;restart|force-reload)do_stop $IOCSsleep 1do_start $IOCS;;*)echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload} [iocs ...]" >&2exit 3;;
esac

以下命令行启动IOC:

root@orangepi5plus:~# ./test.sh start aiDriver
Starting soft IOCs ... aiDriver ... done.
root@orangepi5plus:~# ss -lntp
State     Recv-Q    Send-Q        Local Address:Port          Peer Address:Port    Process
LISTEN    0         128                 0.0.0.0:22                 0.0.0.0:*        users:(("sshd",pid=1383,fd=3))
LISTEN    0         20                  0.0.0.0:5080               0.0.0.0:*        users:(("st.cmd",pid=172122,fd=13))
LISTEN    0         5                 127.0.0.1:20000              0.0.0.0:*        users:(("st.cmd",pid=172122,fd=3),("procServ",pid=172121,fd=3))
LISTEN    0         4                 127.0.0.1:5037               0.0.0.0:*        users:(("adbd",pid=849,fd=5))
LISTEN    0         4096                0.0.0.0:111                0.0.0.0:*        users:(("rpcbind",pid=900,fd=4),("systemd",pid=1,fd=32))
LISTEN    0         4                   0.0.0.0:5075               0.0.0.0:*        users:(("st.cmd",pid=172122,fd=15))
LISTEN    0         4                   0.0.0.0:5555               0.0.0.0:*        users:(("adbd",pid=849,fd=10))
LISTEN    0         4096          127.0.0.53%lo:53                 0.0.0.0:*        users:(("systemd-resolve",pid=901,fd=14))
LISTEN    0         128                    [::]:22                    [::]:*        users:(("sshd",pid=1383,fd=4))
LISTEN    0         4096                   [::]:111                   [::]:*        users:(("rpcbind",pid=900,fd=6),("systemd",pid=1,fd=34))

以下命令行停止IOC:jj

root@orangepi5plus:~# ./test.sh stop aiDriver
Stopping soft IOCs ... aiDriver ... done.
root@orangepi5plus:~# ss -lntp
State      Recv-Q     Send-Q          Local Address:Port           Peer Address:Port     Process
LISTEN     0          128                   0.0.0.0:22                  0.0.0.0:*         users:(("sshd",pid=1383,fd=3))
LISTEN     0          4                   127.0.0.1:5037                0.0.0.0:*         users:(("adbd",pid=849,fd=5))
LISTEN     0          4096                  0.0.0.0:111                 0.0.0.0:*         users:(("rpcbind",pid=900,fd=4),("systemd",pid=1,fd=32))
LISTEN     0          4                     0.0.0.0:5555                0.0.0.0:*         users:(("adbd",pid=849,fd=10))
LISTEN     0          4096            127.0.0.53%lo:53                  0.0.0.0:*         users:(("systemd-resolve",pid=901,fd=14))
LISTEN     0          128                      [::]:22                     [::]:*         users:(("sshd",pid=1383,fd=4))
LISTEN     0          4096                     [::]:111                    [::]:*         users:(("rpcbind",pid=900,fd=6),("systemd",pid=1,fd=34))

将以下test.sh更名为softIOC并复制到/etc/init.d/目录下,IOC应用程序就可以当作系统服务程序一样被启动。

root@orangepi5plus:~# /etc/init.d/softIOC start aiDriver
Starting soft IOCs ... aiDriver ... done.
root@orangepi5plus:~# /etc/init.d/softIOC stop aiDriver
Stopping soft IOCs ... aiDriver ... done.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/868548.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于DPU的云原生计算资源共池管理解决方案

1. 方案背景和挑战 在传统的云环境中&#xff0c;通常存在着不同的技术栈&#xff0c;支撑多样化的计算服务&#xff0c;具体如下&#xff1a; ① OpenStack环境与虚拟化云主机及裸金属服务 OpenStack是一个开源的云计算管理平台项目&#xff0c;它提供了部署和管理大规模计…

深入理解 RTOS 中断处理机制:实战项目与代码解析

中断&#xff0c;如同嵌入式系统的神经反射&#xff0c;实时响应着外部事件&#xff0c;是保证系统实时性和可靠性的关键。在实时操作系统&#xff08;RTOS&#xff09;中&#xff0c;中断处理机制更是重中之重。本文将结合一个具体的项目案例&#xff0c;深入剖析 RTOS 中断处…

LabVIEW高能质子束流密度分布测试系统

LabVIEW平台开发的高能质子束流密度分布测试系统。该系统主要应用于电子器件的抗辐射加固试验&#xff0c;旨在精确测量高能质子束的密度分布&#xff0c;以评估电子器件在辐射环境下的性能表现和耐受能力。 系统组成与设计 硬件组成&#xff1a; 法拉第杯探测器&#xff1a;…

架构面试-分布式存储系统HA高可用原理及应用案例实战

文章目录 CountDownLatchCountDownLatch:同步等待多个线程完成任务的并发组件CountDownLatch&#xff1a;同步等待多个线程完成任务的并发组件主要特点&#xff1a;常用方法&#xff1a;使用示例&#xff1a;总结 CountDownLatch源码剖析之如何基于AQS实现同步阻塞等待CountDow…

域名证书与ssl证书的关系

在数字化时代&#xff0c;网络安全已成为企业和个人用户关注的焦点。域名证书和SSL证书是两种不同的安全工具&#xff0c;它们共同构成了保护网站安全的基础。虽然它们在名称上相似&#xff0c;但它们的作用和重要性各有不同。 域名证书的概念 域名证书&#xff0c;通常指的是…

【ARMv8/v9 GIC 系列 2.4 -- GIC SGI 和 PPI 中断的启用配置】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 GIC SGI 和 PPI 中断的使能配置GICR_ISENABLER0 操作使用举例SummaryGIC SGI 和 PPI 中断的使能配置 GICR_ISENABLER0寄存器(中断设置-使能寄存器0)用于启用相应的SGI(软件生成中断)或PPI(专用外设中断)向CPU接口的转发。每个…

Vue基础知识:Vue3.3出现的defineOptions,如何使用,解决了什么问题?

1.那么为什么会出现defineOptions? 原因说明&#xff1a; 有<script setup></script>语法糖应用之前&#xff0c;如果要定义 props&#xff0c;emits 可以轻而易举地添加一个与 setup 平级的属性。但是用了<script setup>后&#xff0c;就没法这么干了整个…

成长过程,摔倒不要紧,爬起来、改过、前进

无论何时何地&#xff0c;我们都有重头再来的能力&#xff0c;这份生生不息的力量来自天之灵根&#xff1b; 学习过程会有跌倒&#xff0c;这是很正常的节奏次序&#xff0c;不能掩盖自己的过失、自欺欺人&#xff0c;这不是过失&#xff0c;摔倒了就拍拍身上的灰尘&#xff…

算法题:用JS实现删除链表的倒数第N个节点

学习目标&#xff1a; 删除链表的倒数第N个节点 leetcode原题链接 学习内容&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点 示例 1: 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2: 输入&a…

谷粒商城学习笔记-2-分布式组件-SpringCloud Alibaba-Nacos注册中心

文章目录 一&#xff0c;Nacos简介1&#xff0c;简介2&#xff0c;Nacos原理剖析 二&#xff0c;Nacos服务端安装1&#xff0c;下载 nacos-server2&#xff0c;解压启动nacos-server3&#xff0c;验证 三&#xff0c;服务注册步骤1&#xff0c;引用Nacas客户端的Jar包2&#xf…

c++之命名空间详解(namespace)

引例 在学习之前我们首先了来看这样一个情形: 在c语言下&#xff0c;我们写了两个头文件&#xff1a;链表和顺序表的。我们会定义一个type(typedef int type)方便改变数据类型&#xff08;比如将int改成char&#xff09;&#xff0c;来做到整体代换。 但是我们两个头文件里面…

python实现接口自动化

代码实现自动化相关理论 代码编写脚本和工具实现脚本区别是啥? 代码&#xff1a; 优点&#xff1a;代码灵活方便缺点&#xff1a;学习成本高 工具&#xff1a; 优点&#xff1a;易上手缺点&#xff1a;灵活度低&#xff0c;有局限性。 总结&#xff1a; 功能脚本&#xff1a;工…

【C++】BMP图片结构深度解析及其在C++中的操作与应用

引言 BMP&#xff08;Bitmap Image File&#xff09;是一种与设备无关的图像文件格式&#xff0c;它采用了一种非常直接的方式来存储图像数据&#xff0c;即按照图像的行和列顺序&#xff0c;逐像素地存储颜色值。由于其简单性和可移植性&#xff0c;BMP文件在图像处理、图像分…

windows电脑桌面便签在哪里找?

在忙碌的工作中&#xff0c;我们经常会有很多事情需要记住。这时&#xff0c;电脑桌面便签就成为了我们的好帮手。那么&#xff0c;在Windows电脑上&#xff0c;我们该如何找到桌面便签呢&#xff1f;下面&#xff0c;就让我来为大家详细介绍一下。 其实&#xff0c;Windows电…

Failed building wheel for pyaudio Running setup.py clean for pyaudio

从错误信息来看&#xff0c;问题出在 pyaudio 包的构建过程中。具体来说&#xff0c;缺少 portaudio.h 头文件&#xff0c;这通常是因为系统上没有安装 portaudio 库。 以下是解决此问题的步骤&#xff1a; 安装系统依赖&#xff1a; 在大多数基于 Debian 的系统&#xff08;如…

elementui的table的@selection-change阻止事件改变

说明&#xff1a; 最近有个不想说的&#xff08;xxx&#xff09;业务&#xff0c;在表格勾选每一行的时候要触发一系列查询功能&#xff0c;查询失败还要把那个勾勾回退。真实蛋疼&#xff01;表格勾选的默认selection-change是change事件&#xff0c;一般change事件是在完成之…

数据库的操作

【一】库的增删改查 【0】导入数据文件 source D:\bjpowernode.sql 【1】创建数据库 语法&#xff1a; create database [if not exists] 数据库名 [character set 编码字符集]; create databases db1; # 设置库的默认编码 create databases db1 charsetgbk; 【2】查看数据…

Argo怎么使用?

Argo是一款基于Kubernetes的开源工作流引擎&#xff0c;用于创建、调度和监控容器化工作流。以下是关于Argo使用的基本步骤和要点&#xff1a; 1. **安装Argo** - 首先&#xff0c;确保已经安装了Kubernetes集群&#xff0c;并且拥有kubectl命令行工具的访问权限。 - 使用kubec…

告别盲目跟风!1688竞品数据分析实战指南(图文解析)

不管是哪个行业&#xff0c;想把这个做起来&#xff0c;做下去&#xff0c;第一就要学会模仿&#xff0c;不要自己盲目瞎做&#xff0c;因为别人的数据&#xff0c;都是得到了认可的&#xff0c;先模仿后超越&#xff0c;1688运营里面模仿就是要学会看竞品&#xff0c;店雷达总…

【spring boot项目】统一返回结果封装

ResultCode.java package cn.clz.rental.utils; /*** 定义HTTP状态码常量* 这些常量用于表示不同类型的HTTP响应状态。*/ public class ResultCode {// 表示请求成功的状态码public static final Integer SUCCESS 200;// 表示服务器内部错误的状态码public static final Inte…