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 ]
then
        echo "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"
        do
                unset $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=$TAG
                                shift
                                if [ -z $TAG -o $TAG = "#" ] # TAG变量为空或者内容为”#”
                                then
                                        echo "$CONFFILE: Value(s) required for $TAG.";
                                        exit 1
                                else
                                        VALUE=$1
                                        shift
                                fi
                                # 如果多个值跟随,也分配它们
                                while [ $1 != '#'  -a  $# != 0 ]
                                do
                                        VALUE="$VALUE $1"
                                        shift;
                                done
                                eval ${OPTION}=\$VALUE
                                ;;
                *)              echo "$CONFFILE: Unknown option $1."
                                exit 1
                esac
                shift
        done
}

测试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=$1
     
        BOOTDIR=$HOMEDIRS/$LOC_LC/iocBoot/ioc$LOC_LC/
        HOMEDIR=$HOMEDIRS/$IOC_LC
        PIDFILE=$HOMEDIR/$IOC_LC.pid
        ENVFILE=$HOMEDIR/$IOC_LC.env
        IOC_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=$1
        SECTION=`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:   aiDriver

GLOBAL:

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 ]
        then
                TEST_LIST=`grep -i '^AUTO:' "$CONFFILE" | cut -d: -f2-`
        else
                TEST_LIST="$@"
        fi

        CHECKED_LIST=""
        for IOC in $TEST_LIST
        do
                grep -qi "^$IOC:" $CONFFILE
                if [ $? = 0 ]
                then
                        CHECKED_LIST="$CHECKED_LIST $IOC"
                fi
        done
        echo $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_cmdenvopts

echo "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 $MYIOCS
        do
                echo -n "$IOC "
                clear_options           #清除环境变量
                default_options "$IOC"  #设置默认环境变量
                assign_options "GLOBAL" #设置全局设置的环境变量
                assign_options "$IOC"   #设置本IOC的环境变量
                set_cmdenvopts          #用于启动IOC的环境变量字符串,用于procserv的选项字符串

                if [ -d $BOOTDIR ]     # 测试启动目录是否存在
                    then
                    if [ -d $HOMEDIR ] # 测试家目录是否存在
                        then
                        # 测试是否已经有pidfile文件$PIDFILE的进程在运行了,如果是返回1
                        sudo -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 ]
                            then
                            echo -n "<was running> "
                            else
                            # 启动服务进程以及IOC
                            sudo -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 ]
                                then
                                echo -n "<failed> "
                            fi
                        fi

                    else
                        echo -e "\nWarning: Home directory $HOMEDIR does not exist! Ignoring $IOC"
                    fi
                else
                        echo -e "\nWarning: Boot directory $BOOTDIR does not exist! Ignoring $IOC"
                fi
        done
        echo "... done."
}

do_start的测试脚本如下:

echo "========================Test do_start()============================="
default_options aiDriver
assign_options aiDriver
set_cmdenvopts

do_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 $MYIOCS
        do
                echo -n "$IOC "
                clear_options
                default_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 ]
                    then
                    echo -n "<not running> "
                    else
                    sudo -H -u $IOC_USER bash -c "/usr/sbin/start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name procServ"
                    if [ $? = 1 ]
                        then
                        echo -n "<failed> "
                    else
                        sudo -H -u $IOC_USER bash -c "rm -f $PIDFILE"
                    fi
                fi
        done
        echo "... done."
}

do_stop的测试脚本:

echo "========================Test do_start()============================="
default_options aiDriver
assign_options aiDriver
set_cmdenvopts

do_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 0

        echo "Restarting soft IOCs ... "
        STARTDIR=$PWD
        IOCS=`get_iocs $@`
        [ "$IOCS" = "" ] && echo -n "<none> "
        for IOC in $IOCS
        do
                echo -n "$IOC "
                clear_options
                default_options "$IOC"
                assign_options "GLOBAL"
                assign_options "$IOC"
                if [ -d $BOOTDIR ]
                then
                        cd "$BOOTDIR"
# restart it!
                        echo -e "\ndebug: Reloading ioc $IOC"
                        cd "$STARTDIR"
                else
                        echo -e "\nWarning: Boot directory $BOOTDIR does not exist! Entry for $NET ignored!"
                fi
        done
        echo "... done."
}

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

COMMAND=$1
shift
IOCS=`echo $@`

case "$COMMAND" in
  start)
        do_start $IOCS
        ;;
  stop)
        do_stop $IOCS
        ;;
  restart|force-reload)
        do_stop $IOCS
        sleep 1
        do_start $IOCS
        ;;
  *)
        echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload} [iocs ...]" >&2
        exit 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.mfbz.cn/a/774256.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java安装】windows10+JDK21+IDEA

文章目录 一、JDK安装1. 下载完成后按照自己需要的位置安装2. 配置环境变量2.1 JAVA_HOME变量2.2 PATH配置 3. 验证4. helloworld 二、IDEA安装三、IDEA-HelloWorld 一、JDK安装 JDK安装链接 1. 下载完成后按照自己需要的位置安装 2. 配置环境变量 2.1 JAVA_HOME变量 安装…

JVM原理(三):JVM对象回收判定机制与回收算法

如何判断一个对象是否存活(即是否还分配在堆中)&#xff0c;那看他是否还在用。 1. 引用计数算法 这是一种判断方式&#xff0c;相应的方法就是&#xff1a;如果一个对象被引用&#xff0c;那将被引用的对象中的一个计数器加一&#xff0c;引用失效就减一。在任何时刻引用计数…

QT实现GIF动图显示(小白版,可直接copy使用)

需要你自己提前设置好动图的位置&#xff0c;本例中存放于"/Users/PLA/PLA/PLA.gif widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMovie> #include <QLabel>class Widget : public QWidget {Q_OBJECTpublic:explicit Wid…

mssql查询历史执行过的语句日志

SELECT deqs.creation_time,dest.text AS [SQL Text],deqs.execution_count,deqs.total_elapsed_time,deqs.total_worker_time FROM sys.dm_exec_query_stats AS deqs CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest--where dest.text like %这个是我的条件&#…

基于Springboot的智慧养老中心管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Springboot的智慧养老中心管理系统,…

全景图三维3D模型VR全景上传展示H5开发

全景图三维3D模型VR全景上传展示H5开发 3D互动体验平台的核心功能概览 兼容广泛格式&#xff1a;支持OBJ、FBX、GLTF等主流及前沿3D模型格式的无缝上传与展示&#xff0c;确保创意无界。 动态交互探索&#xff1a;用户可自由旋转、缩放、平移模型&#xff0c;深度挖掘每一处…

默安逐日实验室:XDP的应用实践

1. 网络数据包是如何进入进计算机的 众所周知&#xff0c;网络数据包通常需要在TCP/IP协议栈中进行处理&#xff0c;但网络数据包并不直接进入TCP/IP协议栈&#xff1b;相反&#xff0c;他们直接进入网络接口。因此&#xff0c;在数据包进入 TCP/IP 堆栈之前&#xff0c;它们已…

HTML如何在图片上添加文字

HTML如何在图片上添加文字 当我们开发一个页面&#xff0c;插入图片时&#xff0c;需要有一组文字对图片进行描述。那么HTML中如何在图片上添加文字呢&#xff1f;这篇文章告诉你。 先让我们来看下效果图&#xff1a; 句子“这是一张夜空图片”被放置在了图片的左下角。 那么…

谷粒商城学习-10-docker安装mysql

文章目录 一&#xff0c;拉取MySQL镜像1&#xff0c;搜索MySQL的Docker镜像2&#xff0c;拉取MySQL镜像3&#xff0c;查看已经拉取的镜像 二&#xff0c;创建、启动MySQL容器1&#xff0c;使用docker run创建启动容器2&#xff0c;使用docker ps查看运行状态的容器3&#xff0c…

属性描述符初探——Vue实现数据劫持的基础

目录 属性描述符——Vue实现数据劫持的基础 一、属性描述符是什么&#xff1f; ​编辑 1.1、属性描述符示例 1.2、用属性描述符定义属性及获取对象的属性描述符 1.3、带有读取器和设置器的属性描述符 二、使用属性描述符的情景 2.1、封装和数据隐藏 使用getter和setter…

论文写作全攻略:Kimi辅助下的高效学术写作技巧

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 完成论文写作是一个多阶段的过程&#xff0c;涉及到不同的任务和技能。以下是按不同分类总结的向Kimi提问的prompt&#xff0c;以帮助你在论文写作过程中取得成功&#xff1a; 1. 选题与…

使用kali Linux启动盘轻松破解Windows电脑密码

破解分析文章仅限用于学习和研究目的&#xff1b;不得将上述内容用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。谢谢&#xff01;&#xff01; 效果展示&#xff1a; 使用kali Linux可以轻松破解Windows用户及密码 准备阶段&#xff1a; &#xff08…

RedHat9 | kickstart无人值守批量安装

一、知识补充 kickstart Kickstart是一种用于Linux系统安装的自动化工具&#xff0c;它通过一个名为ks.cfg的配置文件来定义Linux安装过程中的各种参数和设置。 kickstart的工作原理 Kickstart的工作原理是通过记录典型的安装过程中所需人工干预填写的各种参数&#xff0c;…

配置基于用户认证的虚拟主机

添加账号abc [rootlocalhost conf.d]# htpasswd -c /etc/httpd/zhanghao abc New password: Re-type new password: Adding password for user abc添加账号tom [rootlocalhost conf.d]# htpasswd /etc/httpd/zhanghao tom New password: Re-type new password: Adding pa…

QT中QDomDocument读写XML文件

一、XML文件 <?xml version"1.0" encoding"UTF-8"?> <Begin><Type name"zhangsan"><sex>boy</sex><school>Chengdu</school><age>18</age><special>handsome</special>&l…

平安养老险蚌埠中心支公司开展“78奋力前行”健步走活动

7月4日&#xff0c;平安养老保险股份有限公司&#xff08;以下简称“平安养老险”&#xff09;蚌埠中心支公司组织员工在张公山公园开展“78奋力前行”健步走活动&#xff0c;传递保险行业的正能量&#xff0c;展现平安养老险的活力与风采。 平安养老险蚌埠中心支公司员工身着…

【瑞吉外卖 | day02】登录功能完善+员工信息的增改查

文章目录 瑞吉外卖 — day021. 完善登录功能1.1 问题分析1.2 实现 2. 新增员工功能2.1 分析2.2 程序执行过程2.3 程序执行中的异常处理 3. 员工信息分页查询3.1 程序执行过程 4. 启用/禁用员工账号4.1 需求分析4.2 程序执行过程4.3 代码修复 5. 编辑员工信息5.1 需求分析5.2 程…

基于DMAIC降低气缸体水套芯磕碰伤率

在制造业的激烈竞争中&#xff0c;产品质量的提升一直是企业追求的目标。气缸体作为汽车发动机的核心部件&#xff0c;其生产过程中的质量控制尤为重要。今天&#xff0c;深圳天行健企业管理咨询公司就来分享一下如何运用DMAIC&#xff08;定义、测量、分析、改进、控制&#x…

Logstash安装插件失败的问题

Logstash安装插件失败的问题 安装 logstash-output-jdbc 失败 报错为&#xff1a; Unable to download data from https://rubygems.org - Net::OpenTimeout: Failed to open TCP connection to rubygems.org:443 (execution expired) (https://rubygems.org/latest_specs.4.…

[GHCTF 2024 新生赛]UP+——入土为安的第一天

注意&#xff1a;这道题需要脱壳&#xff0c;而且需要改特征值&#xff0c;详细请看 [LitCTF 2024]hello_upx——入土为安的第一天-CSDN博客 脱完壳发现有256这个特殊的数&#xff0c;是rc4类型的题&#xff0c;最后有一个异或 a "9F041CEFA92386B6F56F27B96155FD42&qu…
最新文章