簡體   English   中英

如何制作啟動 Python 腳本的 linux 后台進程(在 c 中)

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

我制作了一個 Linux 后台進程(在 c++ 中),它監視一個目錄並嘗試啟動 Python 腳本,如果某個文件出現在該目錄中。 我的問題是負責啟動 Python 腳本的子進程在 execvp function 被調用后立即退出,我不明白為什么。 所有必要的文件都歸根用戶所有。 如果有幫助,這是我的代碼。 提前感謝您的任何指點。 我在發生錯誤的代碼中標記了錯誤。 我還包括要調用的 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 為了理解它失敗的原因,你的程序需要 output 某處的 errno 值; 可能是標准輸出、標准錯誤或您的日志文件。 一個方便的方法是使用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 發送 output 相關的錯誤消息; 例如,如果 Python 找不到您的程序,它將 output “沒有這樣的文件或目錄”到 stderr。

但是,看起來您的 C 程序在調用doWork() ) 之前調用了close(STDERR_FILENO) STDERR_FILENO) 。 根據fork(2) ,子進程繼承父進程的打開文件描述符集的副本。 這意味着在分叉之前調用close(STDERR_FILENO)將導致子進程沒有打開的 stderr 文件描述符。 如果 Python 在執行您的程序時出現任何錯誤,您永遠不會知道,因為 Python 試圖通過不存在的文件描述符通知您。 如果 execvp(3) 成功並且 Python 程序似乎根本沒有運行,那么我建議您從 C 程序中刪除close(STDERR_FILENO)並再次運行所有程序。 在沒有看到 Python 的錯誤消息 output 的情況下,很難確定為什么它無法運行 Python 程序。

順便說一句,我建議不要明確關閉標准輸入、標准輸出和標准錯誤。 根據stdin(3) ,標准流通過調用 exit(3) 和正常程序終止來關閉。

execvp(3) 成功了,我的 Python 程序正在運行,但是我的 Python 程序在它做任何有用的工作之前就退出了

在這種情況下,我不確定問題可能是什么,因為我對 Raspberry Pi 不是很熟悉。 但我認為,如果您在運行 Python 程序之前不關閉標准流,那么您的調試會更輕松。

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM