Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Linux中用C在后台启动进程_C_Linux_Process_Fork - Fatal编程技术网

在Linux中用C在后台启动进程

在Linux中用C在后台启动进程,c,linux,process,fork,C,Linux,Process,Fork,我想做点奇怪的事。我需要启动一个进程logcat,从一个deamon开始,它将在后台运行并打印到终端,而不需要控制stdin。它用于日志记录,因此理想情况下logcat将打印日志消息,同时仍然允许用户输入标准命令并从shell初始化程序。这是我到目前为止所拥有的守护进程的代码。logcat程序启动并显示日志消息,但我无法在stdin中输入任何命令,因为该程序似乎已经控制了stdin int main ( int argc, char** argv, char** env ) { int

我想做点奇怪的事。我需要启动一个进程logcat,从一个deamon开始,它将在后台运行并打印到终端,而不需要控制stdin。它用于日志记录,因此理想情况下logcat将打印日志消息,同时仍然允许用户输入标准命令并从shell初始化程序。这是我到目前为止所拥有的守护进程的代码。logcat程序启动并显示日志消息,但我无法在stdin中输入任何命令,因为该程序似乎已经控制了stdin

int main ( int argc, char** argv, char** env )
{
    int fd;
    if ((fd = open("/dev/console", O_RDWR)) < 0) {
        fd = open("/dev/null", O_RDWR);
    }
    printf("THIS IS A TEST\n");
    dup2(1, fd);
    dup2(2, fd);

    pid_t childpid = fork();

    if(childpid == -1) {
        perror("Failed to fork, logcat not starting");
        return 1;
    }

    if(childpid == 0) {
        //this is the child, exec logcat
        setsid();
        int execReturn = execl("/system/bin/logcat", "logcat", (char *) 0);
    } else {
        //this is the parent do nothing
        close(fd);
        return 0;
    }
    close(fd);
     return 0;
}
int main(int argc、char**argv、char**env)
{
int-fd;
如果((fd=open(“/dev/console”,O_RDWR))<0){
fd=打开(“/dev/null”,O_RDWR);
}
printf(“这是一个测试\n”);
dup2(1,fd);
dup2(2,fd);
pid_t childpid=fork();
if(childpid==-1){
perror(“未能分叉,logcat未启动”);
返回1;
}
if(childpid==0){
//这是孩子,exec logcat
setsid();
int execReturn=execl(“/system/bin/logcat”,“logcat”,“char*)0);
}否则{
//这是父母什么都不做的
关闭(fd);
返回0;
}
关闭(fd);
返回0;
}
谢谢

[死链接]

[上述回程机器档案]

--代码取自上面的链接

执行摘要:

我经常遇到的一件事是Linux守护进程不能正确地对自己进行守护。要正确地进行后台监控,必须遵循以下步骤

  • fork()调用用于创建单独的进程
  • setsid()调用用于将进程与父进程(通常是shell)分离
  • 应该重置文件掩码
  • 当前目录应更改为良性目录
  • 需要重新打开标准文件(stdin、stdout和stderr)
如果不执行这些步骤中的任何一个,都会导致守护进程行为异常。典型症状如下

  • 启动守护进程然后注销将导致终端挂起。这对于ssh来说尤其令人讨厌
  • 从中启动守护程序的目录仍处于锁定状态
  • 在启动守护进程的shell中出现虚假输出
该命令似乎是用于Android开发的——这可能解释了该命令的奇怪位置

您必须修复的关键操作是确保关闭当前的标准输入(终端),并为输入设备打开
/dev/null/

close(0);
if ((fd = open("/dev/null", O_RDONLY)) != 0)
    ...error - failed to open /dev/null!
这意味着您的守护子进程将不会从终端读取任何内容


我想你要做的是:

  • 从命令行运行启动程序,该命令行将标准输入、标准输出和标准错误连接到“终端”
  • 在程序内部,您希望替换标准输入,使其来自
    /dev/null
  • 您希望不使用标准输出—您希望
    logcat
    写入当前标准输出
  • 您可能也希望不使用标准错误
  • 在过程中的某个时刻,您可以正确地执行您的操作(借用@bstperre答案中的链接),确保您连接的终端不是您的控制终端,以便发送到终端的中断和挂断不会影响您的守护进程。管道比您设置的更简单-您应该处理标准输入,保持标准输出和标准错误不变(而不是更改输出和保持输入不变)

    现在,您可能希望输出转到
    /dev/console
    ;如果是这样,那么修改代码以打开
    /dev/console
    是合理的。但是,如果您无法打开
    /dev/console
    ,那么使用
    /dev/null
    是不合理的;您的程序应该报告错误并失败(因为让logcat写入
    /dev/null
    !)没有意义。确保使用
    O_NOCTTY
    标志打开控制台,使其不会成为守护进程的控制终端

    我最后要说的是:

    • 当终端或控制台用于其他用途时,是否确实希望随机文本出现在终端或控制台上
    我不太喜欢这种情况



    另请参见:

    glibc中有专门用于此的功能:

    #include <unistd.h>
    
    ...
    /* We are in the parent, yet */
    daemon(0,0);
    /* Now we are in the child */
    ...
    
    #包括
    ...
    /*我们在父母家,还没有*/
    守护进程(0,0);
    /*现在我们是孩子了*/
    ...
    

    这里有更多详细信息

    非常感谢您的深入回答。正如你所提到的,问题是stdin。我不得不从logcat重定向到stdin,还有一些其他的东西,比如进程的后台监控。这帮我省去了很多压力和烦恼。再次感谢。我真的很感激。这帮了大忙。谢谢你。@Mike-你可能会弄错很多东西。。。我以前漏掉了一些片段,这篇文章是记住所有片段的一个很好的起点。链接似乎已经死了。