使用systemd实现mqtt程序上电自启

service文件组成

控制单元(Unit)

主要包括服务描述、启动顺序和依赖关系

Description:当前服务的简单描述;

Documentation:文档位置;

After:在什么服务之后启动;

Before:在什么服务之前启动;

Wants:表示“弱依赖”关系。某服务停止运行或退出不影响该服务继续运行;

Requires:表示”强依赖”关系。列在其中的Uint模块会在这个服务启动的同时被启动,如果其中任意一个启动失败,这个服务会被终止。某服务停止运行或退出,该服务也必须停止运行。

PartOf:该参数仅用于单元的停止或重启。

服务定义(Service)

Type

定义启动类型。可设置的值如下:

simple(默认值):ExecStart字段启动的进程为主进程;

forking:ExecStart字段以fork()方式启动,父进程退出后,子进程将成为主进程;

oneshot:类似于simple,但只执行一次,Systemd 会等它执行完,才启动其他服务;

dbus:类似于simple,但会等待 D-Bus 信号后启动;;

notify:类似于simple,启动结束后会发出通知信号,然后 Systemd 再启动其他服务;

idle:类似于simple,但是要等到其他任务都执行完,才会启动该服务。一种使用场合是为让该服务的输出,不与其他服务的输出相混;

Environment

为服务设置环境变量

EnvironmentFile

加载包含服务所需环境变量参数的文件。

PIDFile

该服务PID文件的路径(一般位于 /run/ 目录下)。 建议在 Type=forking 的情况下明确设置此选项。 如果设为相对路径,那么表示相对于 /run/ 目录。 systemd 将会在此服务启动完成之后,从此文件中读取主服务进程的PID 。 systemd 不会写入此文件,但会在此服务停止后删除它(若仍然存在)。

ExecStart

启动程序时执行的命令。

ExecReload

重启服务执行的命令。

Restart定义sshd退出后,systemd的重启方式。设置值如下:

no(默认值):退出后不会重启;

on-success:只有正常退出时(退出状态码为0),才会重启;

on-failure:非正常退出时(退出状态码非0),包括被信号终止和超时,才会重启;

on-abnormal:只有被信号终止和超时,才会重启;

on-abort:只有在收到没有捕捉到的信号终止时,才会重启;

on-watchdog:超时退出,才会重启;

always:不管是什么退出原因,总是重启;

服务出现情况与重启对应列表

SuccessExitStatus

额外定义其他的进程"正常退出"状态。 也就是,在退出码"0"、以及表示"正常退出"的 SIGHUP, SIGINT, SIGTERM, SIGPIPE 信号之外, 再额外添加一组表示"正常退出"的退出码或信号。 可以设为一系列以空格分隔的数字退出码或者信号名称, 例如:SuccessExitStatus=1 2 8 SIGKILL\n\n表示当进程的退出码是 1, 2, 8 或被 SIGKILL 信号终止时, 都可以视为"正常退出"。如果多次使用此选项, 那么最终的结果将是多个列表的合并。 如果将此选项设为空, 那么先前设置的列表 将被清空。

RestartSec

重启服务之前需要等待的秒数。

安装部分(Install)

用来定义如何启动以及是否开机启动。

WantedBy 表示该服务所在的Target。 该项目就是将此unit 安装到哪个target 里面去的意思;

multi-user.target是systemd默认启动的Target,表示在这个组里的所有服务,都开机启动。

# 查看当前系统的所有 Target
$ systemctl list-unit-files --type=target

# 查看一个 Target 包含的所有 Unit
$ systemctl list-dependencies multi-user.target

# 查看启动时的默认 Target
$ systemctl get-default

# 设置启动时的默认 Target
$ systemctl set-default multi-user.target

# 切换 Target 时,默认不关闭前一个 Target 启动的进程,systemctl isolate 命令改变这种行为,关闭前一个 Target 里面所有不属于后一个 Target 的进程

实战

创建服务文件

cd /lib/systemd/system
sudo vim myprogram.service

编写服务文件内容

[Unit]
Description=myprogram //当前服务的简单描述
After=network.target //在网络模块运行成功后再启动服务

[Service]
Type=idle //等到其他任务执行完才会启动该服务
Restart=on-failure//如果启动服务失败
RestartSec=5//则5秒后重新启动
ExecStart=/usr/bin/rs485_mqtt -t 1800 -o 2 -d -c //开始运行程序

[Install]
WantedBy=multi-user.target

保存并关闭文件

systemctl是一个systemd工具,负责控制systemd系统和管理系统服务。

当新增或修改service单元文件时,需要系统重新加载所有修改过的配置文件

sudo systemctl daemon-reload

设置开机启用

sudo systemctl enable myprogram.service

关闭开机启用

sudo systemctl disable myprogram.service

启动服务

sudo systemctl start myprogram.service

关闭服务后,进程会全部被kill掉

sudo systemctl stop myprogram.service

查看服务的状态

systemctl status myprogram.service

实战过程中遇到的问题

1.上电自启服务,程序总是退出,查看日志系统发现程序总是是在deamon()函数附近退出

原因:systemd自启服务给程序fork了一个进程来执行程序,假设进程号为1000,但是由于程序中调用了deamon(),该函数调用了fork()又创建了一个进程,假设进程号为1001,此时程序不在1000这个进程中运行了,而是在1001这个进程上运行,然后systemd自启服务发现程序不在1000这个进程中运行了,就把程序杀死了。

解决办法就是systemd自启服务中的程序千万别调用deamon函数

2.上述问题解决完又出现新问题,程序在mqtt初始化函数附近退出

原因:设备在上电后,网络模块没这么快加载完毕,而mqtt程序又是需要联网才能正常运行的

解决办法在mqtt初始化代码前中加入sleep()阻塞一段,等待设备联网成功后再执行mqtt初始化,到此程序一切正常,大功告成。

systemd启动服务管理机制,有如下好处:

平行处理所有服务,加速开机流程:不相依服务可以同时启动 一经要求就响应的on-demand 启动方式:管理系统服务只需systemctl一个指令 服务相依性的自我检查:无需管理员进行相依性分析,在启动某个服务前会自动帮管理员启动未启动的依赖服务; 依daemon 功能分类:每个服务为一个unit单元,并有不同的type(service, socket, target, path, snapshot, etc.); 将多个daemons 集合成为一个群组:类似于systemV中的runlevel,将许多的功能集合为一个target选项,作为操作环境,亦即执行了多个daemon; 向下兼容旧有的init 服务脚本:如使用init 3可以切换到图形界面。

  但是systemd不能完全取代systemv。其中有runlevel对应不完全,systemctl支持语法有限制,不可自定义参数;管理员手动启动服务无法通过systemd进行管理;编制systemd启动设定,不能存在互动机制等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值