문제

내 Rasperry Pi에서 omxplayer용 원격 제어 프로그램을 작성하려고 합니다.

하위 프로세스에서 omxplayer가 정상적으로 실행되도록 할 수 있지만 실제로 하위 프로세스에 명령을 보내기 위해 파이프가 올바르게 작동하도록 할 수는 없는 것 같습니다.

int fd_pipe[2];
pipe (fd_pipe);

while(1) {  // main accept() loop

    printf("server: got connection from %s\n", s);

    /* Attempt to fork and check for errors */
    if( (pid=fork()) == -1){
        fprintf(stderr,"Fork error. Exiting.\n");  /* something went wrong */
        exit(1);
    }

    if (pid==0) 
    { // this is the child process
        dup2(0, fd_pipe[0]);
        close(fd_pipe[1]);


        if(execl("/usr/bin/top","top",NULL) == -1){
            fprintf(stderr,"execl Error!");
            exit(1);
        }

        //try and send command here
        write(fd_pipe[0], "q", 1);

        exit(0);

    } else {

        close(new_fd);  // parent doesn't need this
        dup2(1, fd_pipe[1]);

        //try and send here too
        write(fd_pipe[0], "q", 1);
    }
}

top으로 테스트하고 프로그램을 실행했을 때 터미널 창에 top 출력이 나타나는 것을 볼 수 있고 창에서 q 명령을 볼 수 있지만 하위 프로세스가 아닌 상위 프로세스로 이동하는 것처럼 보입니다.파이프에 문제가 있는 걸까요? 아니면 생성된 하위 프로세스에 명령을 보낼 수 없는 걸까요?

파이프에서 stdin으로 복사하기 위해 하위 dup2 문을 변경해 보았습니다.

        { // this is the child process
        dup2(fd_pipe[0], 0);

그러나 tty get 메시지 실패로 인해 top이 시작되지 않습니다.

도움이 되었습니까?

해결책

터미널을 조작할 수 있을 것으로 예상되는 프로그램과 상호 작용하려면 의사 tty를 사용해야 합니다.이렇게 하면 다음을 피할 수 있습니다. failed tty get 오류.

/*...*/
#include <pty.h>

void do_child () {
    if (execlp("top", "top", (const char *)0) < 0) {
        perror("exec top");
        exit(EXIT_FAILURE);
    }
    /* NOTREACHED */
}

void do_parent (int fd, pid_t p) {
    sleep(5);
    char r;
    write(fd, "q", 1);
    while (read(fd, &r, 1) > 0) { write(1, &r, 1); }
    waitpid(p, 0, 0);
    close(fd);
}

int main () {
    int fd;
    pid_t p = forkpty(&fd, 0, 0, 0);
    switch (p) {
    case 0:  do_child();
             /* NOTREACHED */
    case -1: perror("forkpty");
             exit(EXIT_FAILURE);
    default: break;
    }
    do_parent(fd, p);
    return 0;
}

참고하세요 forkpty POSIX는 아니지만 UNIX의 BSD 및 Linux 버전에서 사용할 수 있는 인터페이스입니다.

실행할 수 있습니다 top 일괄 모드에서는 명령을 사용하여 종료할 수 없습니다.당신은 그것을 죽여야합니다.

void do_child () {
    if (execlp("top", "top", "-b", (const char *)0) < 0) {
        perror("exec top");
        exit(EXIT_FAILURE);
    }
    /* NOT REACHED */
}

void do_parent (pid_t p) {
    sleep(5);
    if (kill(p, SIGINT) < 0) {
        perror("kill");
        exit(EXIT_FAILURE);
    }
    waitpid(p, 0, 0);
}

int main () {
    pid_t p;
    switch ((p = fork())) {
    case 0:  do_child();
    case -1: perror("fork"); exit(EXIT_FAILURE);
    default: break;
    }
    do_parent(p);
    return 0;
}

배치 모드로 실행하면 더 간단한 호출(예: popen Mux에서 알 수 있듯이) 해당 호출이 하위 프로세스 ID를 반환하지 않는 한 이를 종료할 수 없습니다( pkill, 또는 프로세스 테이블을 조사하여 종료할 올바른 하위 프로세스를 찾으세요.)

사용법에 대해 헷갈리시는 것 같아요 dup2.매뉴얼 페이지에서는 다음 용어를 사용합니다. oldfd 그리고 newfd, 그리고 이는 다음을 의미합니다 oldfd 될 것입니다 newfd.설명을 위해 여기에 stdout 및 stderr을 로그 파일로 리디렉션하고 함수를 호출한 다음 나중에 stdout 및 stderr을 복원하는 간단한 프로그램이 있습니다.

void do_something () {
    fputs("Error message\n", stderr);
    puts("This is regular output.");
    fputs("Error message\n", stderr);
    puts("This is regular output.");
}

int main () {
    int fd = creat("/tmp/output.log", 0664);
    int outfd = dup(fileno(stdout));
    int errfd = dup(fileno(stderr));
    fflush(stdout);
    fflush(stderr);
    dup2(fd, fileno(stdout));
    dup2(fd, fileno(stderr));
    setlinebuf(stdout);

    do_something();

    fflush(stdout);
    fflush(stderr);
    dup2(outfd, fileno(stdout));
    dup2(errfd, fileno(stderr));
    close(outfd);
    close(errfd);

    fputs("Error to the screen\n", stderr);
    puts("Regular output to screen");
    fputs("Error to the screen\n", stderr);
    puts("Regular output to screen");

    return 0;
}

Mux가 지적했듯이 프로그램은 파이프의 잘못된 끝에 쓰고 있습니다.그만큼 pipe 명령은 단방향 파일 설명자 쌍을 반환합니다. fd_pipe[1] 에서 읽을 수 있습니다 fd_pipe[0].

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top