简体   繁体   English

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

[英]How can I make a linux background process (in c) that launches a Python script

I made a Linux background process (in c++) that monitors a directory and attempts to launch a Python script if a certain file appears in that directory.我制作了一个 Linux 后台进程(在 c++ 中),它监视一个目录并尝试启动 Python 脚本,如果某个文件出现在该目录中。 My issue is that the child process responsible for launching the Python script exits immediately after the execvp function is called and I can't understand why.我的问题是负责启动 Python 脚本的子进程在 execvp function 被调用后立即退出,我不明白为什么。 All of the necessary files are under root's ownership.所有必要的文件都归根用户所有。 Here is my code if it helps.如果有帮助,这是我的代码。 Thank you in advance for any pointers.提前感谢您的任何指点。 I have marked the error in my code where the error occurs.我在发生错误的代码中标记了错误。 I have also included the Python script to be called我还包括要调用的 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 script (AKA RFCOMMOut.py) 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")

The question is a little unclear, so I'll try to take a few different educated guesses at what the problem is and address each one individually.这个问题有点不清楚,所以我将尝试对问题所在进行一些不同的有根据的猜测,并分别解决每个问题。

TL;DR: Remove close(STDOUT_FILENO) and close(STDERR_FILENO) to get more debugging information which will hopefully point you in the right direction. TL;DR:删除close(STDOUT_FILENO)close(STDERR_FILENO)以获取更多调试信息,这有望为您指明正确的方向。

execvp(3) is returning -1 execvp(3) 返回 -1

According to the execvp(3) documentation, execvp(3) sets errno when it fails.根据execvp(3)文档, execvp(3) 在失败时设置errno In order to understand why it is failing, your program will need to output the value of errno somewhere;为了理解它失败的原因,你的程序需要 output 某处的 errno 值; perhaps stdout, stderr, or your log file.可能是标准输出、标准错误或您的日志文件。 A convenient way to do this is to use perror(3) .一个方便的方法是使用perror(3) For example:例如:

#include <stdio.h>
...
void doWork() {
  ...
  } else {
    int error = execvp(arguments[0], arguments);
    if(error == -1) {
      perror("execvp() failed");
    }
  }
  ...
}

Without knowing what that errno value is, it will be difficult to identify why execvp(3) is failing.在不知道 errno 值是什么的情况下,很难确定 execvp(3) 失败的原因。

execvp(3) is succeeding, but my Python program doesn't appear run execvp(3) 成功,但我的 Python 程序似乎没有运行

execvp(3) succeeding means that the Python interpreter has successfully been invoked (assuming that there is no program in your PATH that is named "python", but is not actually a Python interpreter). execvp(3) 成功意味着 Python 解释器已成功调用(假设您的 PATH 中没有名为“python”的程序,但实际上不是 Python 解释器)。 If your program doesn't appear to be running, that means Python is having difficulty loading your program.如果您的程序似乎没有运行,这意味着 Python 无法加载您的程序。 To my knowledge, Python will always output relevant error messages in this situation to stderr;据我所知,在这种情况下,Python 总是会向 stderr 发送 output 相关的错误消息; for example, if Python cannot find your program, it will output "No such file or directory" to stderr.例如,如果 Python 找不到您的程序,它将 output “没有这样的文件或目录”到 stderr。

However, it looks like your C program is calling close(STDERR_FILENO) before calling doWork() .但是,看起来您的 C 程序在调用doWork() ) 之前调用了close(STDERR_FILENO) STDERR_FILENO) 。 According to fork(2) , child processes inherit copies of their parent's set of open file descriptors.根据fork(2) ,子进程继承父进程的打开文件描述符集的副本。 This means that calling close(STDERR_FILENO) before forking will result in the child process not having an open stderr file descriptor.这意味着在分叉之前调用close(STDERR_FILENO)将导致子进程没有打开的 stderr 文件描述符。 If Python is having any errors executing your program, you'll never know, since Python is trying to notify you through a file descriptor that doesn't exist.如果 Python 在执行您的程序时出现任何错误,您永远不会知道,因为 Python 试图通过不存在的文件描述符通知您。 If execvp(3) is succeeding and the Python program appears to not run at all, then I recommend you remove close(STDERR_FILENO) from your C program and run everything again.如果 execvp(3) 成功并且 Python 程序似乎根本没有运行,那么我建议您从 C 程序中删除close(STDERR_FILENO)并再次运行所有程序。 Without seeing the error message output by Python, it will be difficult to identify why it is failing to run the Python program.在没有看到 Python 的错误消息 output 的情况下,很难确定为什么它无法运行 Python 程序。

As an aside, I recommend against explicitly closing stdin, stdout, and stderr.顺便说一句,我建议不要明确关闭标准输入、标准输出和标准错误。 According to stdin(3) , the standard streams are closed by a call to exit(3) and by normal program termination.根据stdin(3) ,标准流通过调用 exit(3) 和正常程序终止来关闭。

execvp(3) is succeeding, my Python program is running, but my Python program exits before it does any useful work execvp(3) 成功了,我的 Python 程序正在运行,但是我的 Python 程序在它做任何有用的工作之前就退出了

In this case, I'm not sure what the problem might be, since I'm not very familiar with Raspberry Pi.在这种情况下,我不确定问题可能是什么,因为我对 Raspberry Pi 不是很熟悉。 But I think you'll have an easier time debugging if you don't close the standard streams before running the Python program.但我认为,如果您在运行 Python 程序之前不关闭标准流,那么您的调试会更轻松。

Hope this helps.希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何配置后台进程,该进程在django项目中按指定的时间间隔运行python脚本 - How can i configure a background process which runs a python script in my django project at specified intervals of time 如何在 C# 中使用 async 从称为进程的 python 脚本中获取我需要的结果? - How can I use async in C# to get the result I need from a python script called as a process? 如何与 Python 中已经运行的 Linux 进程通信? - How can I communicate with an already running Linux process in Python? 如何在linux中读取python中进程的内存? - How can I read the memory of a process in python in linux? 如何在Linux上强制在后台运行Python脚本 - How to force a Python script run in background on Linux 如何在后台/作为进程运行python脚本? - How to run python script on background/as a process? 如何在linux上的后台使用python捕获mouseevents和keyevent - How can I capture mouseevents and keyevents using python in background on linux 如何在python中始终使进程在后台运行? - How can I have a process always running in background in python? 如何启动进程并将其放入python的后台? - How can I start a process and put it to background in python? 如果在Linux上使用此python脚本,如何获取价值? - How can i get a value out if this python script on linux?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM