我怎样才能创建启动 Python 脚本的 linux 后台进程(在 c 中)
How can I make a linux background process (in c) that launches a Python script
我创建了一个 Linux 后台进程(在 C++ 中),它监视一个目录并在该目录中出现某个文件时尝试启动 Python 脚本。我的问题是负责启动 Python 脚本的子进程在调用 execvp 函数后立即退出,我不明白为什么。所有必要的文件都在 root 的所有权之下。如果有帮助,这是我的代码。提前感谢您的任何指点!我在发生错误的代码中标记了错误。我还包含了要调用的 Python 脚本
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
using namespace std;
char* arguments[3];
FILE* fd;
const char* logFilePath = "/home/BluetoothProject/Logs/fileMonitorLogs.txt";
char* rfcommPath = (char*)"/home/BluetoothProject/RFCOMMOut.py";
void logToFile(const char*);
void doWork();
void logToFile(const char* str) {
fd = fopen(logFilePath, "a");
fprintf(fd, "%s\n", str);
fclose(fd);
}
int main() {
arguments[0] = (char*)"python";
arguments[1] = rfcommPath;
arguments[2] = NULL;
pid_t pid = fork();
if(pid < 0) {
printf("Fork failed");
exit(1);
} else if(pid > 0) {
exit(EXIT_SUCCESS);
}
umask(0);
pid_t sid = setsid();
if(sid < 0) {
logToFile("setsid() didn't work.");
exit(1);
}
if ((chdir("/")) < 0) {
logToFile("chdir() didn't work.");
exit(EXIT_FAILURE);
}
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
doWork();
}
void doWork() {
pid_t pid = fork();
if(pid < 0) {
logToFile("doWork() fork didn't work.");
} else if(pid > 0) {
int status = 0;
waitpid(pid, &status, 0);
if(WEXITSTATUS(status) == 1) {
logToFile("Child process exited with an error.");
}
} else {
int error = execvp(arguments[0], arguments); //Here is where the error is
if(error == -1) {
logToFile("execvp() failed.");
}
exit(1);
}
}
Python 脚本(又称 RFCOMMOut.py)
import RPi.GPIO as gpio
import serial
led_state = 0
led_pin = 11
gpio.setmode(gpio.BOARD)
gpio.setwarnings(False)
gpio.setup(led_pin, gpio.OUT)
try:
ser = serial.Serial(port = '/dev/rfcomm0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS)
except IOException as e:
logFile = open("/home/BluetoothProject/Logs/fileMonitorLogs.txt", "a")
logFile.write("(First error handler) There was an exception:\n")
logFile.write(str(e))
logFile.write("\n")
logFile.close()
#gpio.output
def process_input(input):
global led_state
if input == "I have been sent.\n":
if led_state == 1:
led_state = 0
gpio.output(led_pin, led_state)
else:
led_state = 1
gpio.output(led_pin, led_state)
while True:
try:
transmission = ser.readline()
process_input(transmission)
except IOError as e:
logFile = open("/home/BluetoothProject/Logs/fileMonitorLogs.txt", "a")
logFile.write("(second error handler) There was an exception:\n")
logFile.write(str(e))
logFile.write("\n")
logFile.close()
break
led_state = 0
gpio.output(led_pin, led_state)
gpio.cleanup()
print("End of program\n")
这个问题有点不清楚,所以我将尝试对问题所在进行一些不同的有根据的猜测,然后逐一解决。
TL;DR:删除 close(STDOUT_FILENO)
和 close(STDERR_FILENO)
以获得更多调试信息,这有望为您指明正确的方向。
execvp(3) 返回 -1
根据execvp(3) documentation, execvp(3) sets errno when it fails. In order to understand why it is failing, your program will need to output the value of errno somewhere; perhaps stdout, stderr, or your log file. A convenient way to do this is to use perror(3)。例如:
#include <stdio.h>
...
void doWork() {
...
} else {
int error = execvp(arguments[0], arguments);
if(error == -1) {
perror("execvp() failed");
}
}
...
}
不知道 errno 值是多少,将很难确定 execvp(3) 失败的原因。
execvp(3)成功了,但是我的Python程序没有出现运行
execvp(3) 成功意味着 Python 解释器已成功调用(假设您的 PATH 中没有名为 "python" 的程序,但实际上不是 Python 解释器)。如果您的程序似乎没有 运行ning,这意味着 Python 无法加载您的程序。据我所知,Python 总是会在这种情况下将相关的错误信息输出到 stderr;例如,如果 Python 找不到你的程序,它将输出 "No such file or directory" 到 stderr。
但是,看起来您的 C 程序在调用 doWork()
之前先调用了 close(STDERR_FILENO)
。根据 fork(2),子进程继承其父进程的 open 文件描述符集的副本。这意味着在分叉之前调用 close(STDERR_FILENO)
将导致子进程没有打开的 stderr 文件描述符。如果 Python 在执行您的程序时出现任何错误,您永远不会知道,因为 Python 试图通过一个不存在的文件描述符来通知您。如果 execvp(3) 成功并且 Python 程序似乎根本没有 运行,那么我建议您从 C 程序中删除 close(STDERR_FILENO)
并再次 运行 所有内容。如果没有看到 Python 输出的错误消息,将很难确定 运行 Python 程序失败的原因。
顺便说一句,我建议不要显式关闭 stdin、stdout 和 stderr。根据 stdin(3),标准流通过调用 exit(3) 和正常程序终止来关闭。
execvp(3) 成功,我的 Python 程序正在 运行ning,但是我的 Python 程序在它做任何有用的工作之前就退出了
在这种情况下,我不确定可能是什么问题,因为我对 Raspberry Pi 不是很熟悉。但我认为,如果在 运行 启动 Python 程序之前不关闭标准流,调试会更轻松。
希望这对您有所帮助。
我创建了一个 Linux 后台进程(在 C++ 中),它监视一个目录并在该目录中出现某个文件时尝试启动 Python 脚本。我的问题是负责启动 Python 脚本的子进程在调用 execvp 函数后立即退出,我不明白为什么。所有必要的文件都在 root 的所有权之下。如果有帮助,这是我的代码。提前感谢您的任何指点!我在发生错误的代码中标记了错误。我还包含了要调用的 Python 脚本
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
using namespace std;
char* arguments[3];
FILE* fd;
const char* logFilePath = "/home/BluetoothProject/Logs/fileMonitorLogs.txt";
char* rfcommPath = (char*)"/home/BluetoothProject/RFCOMMOut.py";
void logToFile(const char*);
void doWork();
void logToFile(const char* str) {
fd = fopen(logFilePath, "a");
fprintf(fd, "%s\n", str);
fclose(fd);
}
int main() {
arguments[0] = (char*)"python";
arguments[1] = rfcommPath;
arguments[2] = NULL;
pid_t pid = fork();
if(pid < 0) {
printf("Fork failed");
exit(1);
} else if(pid > 0) {
exit(EXIT_SUCCESS);
}
umask(0);
pid_t sid = setsid();
if(sid < 0) {
logToFile("setsid() didn't work.");
exit(1);
}
if ((chdir("/")) < 0) {
logToFile("chdir() didn't work.");
exit(EXIT_FAILURE);
}
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
doWork();
}
void doWork() {
pid_t pid = fork();
if(pid < 0) {
logToFile("doWork() fork didn't work.");
} else if(pid > 0) {
int status = 0;
waitpid(pid, &status, 0);
if(WEXITSTATUS(status) == 1) {
logToFile("Child process exited with an error.");
}
} else {
int error = execvp(arguments[0], arguments); //Here is where the error is
if(error == -1) {
logToFile("execvp() failed.");
}
exit(1);
}
}
Python 脚本(又称 RFCOMMOut.py)
import RPi.GPIO as gpio
import serial
led_state = 0
led_pin = 11
gpio.setmode(gpio.BOARD)
gpio.setwarnings(False)
gpio.setup(led_pin, gpio.OUT)
try:
ser = serial.Serial(port = '/dev/rfcomm0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS)
except IOException as e:
logFile = open("/home/BluetoothProject/Logs/fileMonitorLogs.txt", "a")
logFile.write("(First error handler) There was an exception:\n")
logFile.write(str(e))
logFile.write("\n")
logFile.close()
#gpio.output
def process_input(input):
global led_state
if input == "I have been sent.\n":
if led_state == 1:
led_state = 0
gpio.output(led_pin, led_state)
else:
led_state = 1
gpio.output(led_pin, led_state)
while True:
try:
transmission = ser.readline()
process_input(transmission)
except IOError as e:
logFile = open("/home/BluetoothProject/Logs/fileMonitorLogs.txt", "a")
logFile.write("(second error handler) There was an exception:\n")
logFile.write(str(e))
logFile.write("\n")
logFile.close()
break
led_state = 0
gpio.output(led_pin, led_state)
gpio.cleanup()
print("End of program\n")
这个问题有点不清楚,所以我将尝试对问题所在进行一些不同的有根据的猜测,然后逐一解决。
TL;DR:删除 close(STDOUT_FILENO)
和 close(STDERR_FILENO)
以获得更多调试信息,这有望为您指明正确的方向。
execvp(3) 返回 -1
根据execvp(3) documentation, execvp(3) sets errno when it fails. In order to understand why it is failing, your program will need to output the value of errno somewhere; perhaps stdout, stderr, or your log file. A convenient way to do this is to use perror(3)。例如:
#include <stdio.h>
...
void doWork() {
...
} else {
int error = execvp(arguments[0], arguments);
if(error == -1) {
perror("execvp() failed");
}
}
...
}
不知道 errno 值是多少,将很难确定 execvp(3) 失败的原因。
execvp(3)成功了,但是我的Python程序没有出现运行
execvp(3) 成功意味着 Python 解释器已成功调用(假设您的 PATH 中没有名为 "python" 的程序,但实际上不是 Python 解释器)。如果您的程序似乎没有 运行ning,这意味着 Python 无法加载您的程序。据我所知,Python 总是会在这种情况下将相关的错误信息输出到 stderr;例如,如果 Python 找不到你的程序,它将输出 "No such file or directory" 到 stderr。
但是,看起来您的 C 程序在调用 doWork()
之前先调用了 close(STDERR_FILENO)
。根据 fork(2),子进程继承其父进程的 open 文件描述符集的副本。这意味着在分叉之前调用 close(STDERR_FILENO)
将导致子进程没有打开的 stderr 文件描述符。如果 Python 在执行您的程序时出现任何错误,您永远不会知道,因为 Python 试图通过一个不存在的文件描述符来通知您。如果 execvp(3) 成功并且 Python 程序似乎根本没有 运行,那么我建议您从 C 程序中删除 close(STDERR_FILENO)
并再次 运行 所有内容。如果没有看到 Python 输出的错误消息,将很难确定 运行 Python 程序失败的原因。
顺便说一句,我建议不要显式关闭 stdin、stdout 和 stderr。根据 stdin(3),标准流通过调用 exit(3) 和正常程序终止来关闭。
execvp(3) 成功,我的 Python 程序正在 运行ning,但是我的 Python 程序在它做任何有用的工作之前就退出了
在这种情况下,我不确定可能是什么问题,因为我对 Raspberry Pi 不是很熟悉。但我认为,如果在 运行 启动 Python 程序之前不关闭标准流,调试会更轻松。
希望这对您有所帮助。