我如何制作一个启动Python脚本的linux后台进程(在c中)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我如何制作一个启动Python脚本的linux后台进程(在c中)相关的知识,希望对你有一定的参考价值。

我制作了一个Linux后台进程(在c ++中),该进程监视目录,并在该目录中出现某个文件时尝试启动Python脚本。我的问题是,调用execvp函数后,负责启动Python脚本的子进程立即退出,我不明白为什么。所有必需的文件均由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)文档,execvp(3)在失败时设置errno。为了理解为什么它失败,您的程序将需要在某个地方输出errno的值。也许是stdout,stderr或您的日志文件。一种方便的方法是使用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解释器)。如果您的程序似乎没有运行,则意味着Python难以加载您的程序。据我所知,在这种情况下,Python始终会向stderr输出相关的错误消息。例如,如果Python无法找到您的程序,它将向stderr输出“没有这样的文件或目录”。

但是,似乎您的C程序在调用close(STDERR_FILENO)之前正在调用doWork()。根据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程序正在运行,但是我的Python程序在执行任何有用的工作之前就退出了

在这种情况下,由于我对Raspberry Pi不太熟悉,所以我不确定是什么问题。但是,如果您在运行Python程序之前不关闭标准流,那么我认为调试起来会更容易。

希望这会有所帮助。

以上是关于我如何制作一个启动Python脚本的linux后台进程(在c中)的主要内容,如果未能解决你的问题,请参考以下文章

在启动时保持 bash 脚本在后台循环的最佳方法是啥 - Linux?

即使在我注销 SSH 后,如何在后台运行 Python 脚本?

想请大神写一个在linux环境下用shell脚本控制jar的启动和停止,类似于一个后台服务那种的。

linux 添加自动启动脚本

linux shell脚本如何启动一个java进程

OS-Linux-后台启动与前台启动导致的差异故障-文件加载异常