Domanda

Ho preparato un programma che emula shell (cmd) interfaccia utilizzando tubi. Ci sono due versioni del programma: 1. Utilizzando un tubo (con un tubo da genitore a figlio comunicazione) 2. Utilizzando doppio tubo (utilizzando due tubi di padre in figlio e da bambino a genitore di comunicare).

Quindi, il primo programma fornisce l'interfaccia desiderata e lavora come voglio, ma non può raggiungere lo stesso risultato (interfaccia) nel secondo programma (usando dup2 () e simili).

Quindi, io relè sul vostro aiuto e mettere entrambi i codici di seguito.

B.S .: Si può compilare e provare entrambi i programmi con lo stesso modo in cui l'utilizzo di questi comandi:

$ gcc -o prog1.c prog1

Esegui Successivo let:

$ ./prog1

Avanti Corriamo nuovo terminal e cercare di scrivere alcuni dati input.txt:

$ echo PWD> input.txt

E poi guardare il risultato nel primo terminale.

(Questa lavorando bene per il primo programma, ma ho bisogno di ottenere questo lavoro spirito la stessa interfaccia nel secondo programma)

Codice del primo programma (che funziona benissimo):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>

void do_child(int data_pipe[]) {
    int c;
    int rc;
    close(data_pipe[1]);

    dup2(data_pipe[0], 0); /* This string provides the desired interface of the program */

    char* cmd[] = { "bash", (char *)0 };
    execvp("bash", cmd);

    while ((rc = read(data_pipe[0], &c, 1)) > 0) 
    {
        putchar(c);
    }
    exit(0);
}

void do_parent(int data_pipe[])
{
    int c;
    int rc;
    FILE *in;

    close(data_pipe[0]);

    while (1)
    {
        in = fopen("input.txt", "r");
        while ((c = fgetc(in)) > 0) 
        {
            rc = write(data_pipe[1], &c, 1);
            if (rc == -1) 
            {
                perror("Parent: write");
                close(data_pipe[1]);
                exit(1);
            }
        }
        fclose(in);
    }
    close(data_pipe[1]);
    exit(0);
}

int main(int argc, char* argv[])
{
    int data_pipe[2];
    int pid;
    int rc;

    umask(0);
    mknod("input.txt", S_IFIFO|0666, 0);

    rc = pipe(data_pipe);
    if (rc == -1) 
    {
        perror("pipe");
        exit(1);
    }
    pid = fork();
    switch (pid) 
    {
    case -1:
        perror("fork");
        exit(1);
    case 0:
        do_child(data_pipe);
    default:
        do_parent(data_pipe);
    }
    return 0;
}

Codice del secondo programma (devono essere corretti un po '):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>

/* Original version got from http://www.iakovlev.org */

int parent_to_child[2];
int child_to_parent[2];

void do_parent()
{
    int c;
    char ch;
    int rc;
    FILE *in;

    close(child_to_parent[1]); /* we don't need to write to this pipe.  */
    close(parent_to_child[0]); /* we don't need to read from this pipe. */

    while (1)
    {
        in = fopen("input.txt", "r");
        while ((c = fgetc(in)) > 0) {
            ch = (char)c;
            /* write to child */
            rc = write(parent_to_child[1], &ch, 1);
            if (rc == -1) {
                perror("child: write");
                close(child_to_parent[0]);
                close(parent_to_child[1]);
                exit(1);
            }
            /* read back from child */
            rc = read(child_to_parent[0], &ch, 1);
            c = (int)ch;
            if (rc <= 0) {
                perror("parent: read");
                close(child_to_parent[0]);
                close(parent_to_child[1]);
                exit(1);
            }
            putchar(c);
        }
        fclose(in);
    }
    close(child_to_parent[0]);
    close(parent_to_child[1]);
    exit(0);
}

void do_child()
{
    int c;
    char ch;
    int rc;

    close(parent_to_child[1]); /* we don't need to write to this pipe.  */
    close(child_to_parent[0]); /* we don't need to read from this pipe. */

    //dup2(parent_to_child[0], STDIN_FILENO);
    //dup2(child_to_parent[1], STDOUT_FILENO);

    /* Some dup2() routines must be added here 
    to get this working as the first program above */

    char* cmd[] = { "bash", (char *)0 };
    execvp("bash", cmd);

    while (read(parent_to_child[0], &ch, 1) > 0) {
        c = (int)ch;
        ch = (char)c;
        putchar(ch);
        rc = write(child_to_parent[1], &ch, 1);
        if (rc == -1) {
            perror("child: write");
            close(parent_to_child[0]);
            close(child_to_parent[1]);
            exit(1);
        }
    }
    close(parent_to_child[0]);
    close(child_to_parent[1]);
    exit(0);
}

int main(int argc, char* argv[])
{
    int pid;
    int rc;

    umask(0);
    mknod("input.txt", S_IFIFO|0666, 0);    

    rc = pipe(parent_to_child);
    if (rc == -1) {
        perror("main: pipe parent_to_child");
        exit(1);
    }

    rc = pipe(child_to_parent);
    if (rc == -1) {
        perror("main: pipe child_to_parent");
        exit(1);
    }

    pid = fork();
    switch (pid) {
    case -1:
        perror("main: fork");
        exit(1);
    case 0:
        do_child();
    default:
        do_parent();
    }
    return 0;
}
È stato utile?

Soluzione

La differenza principale è qui:

    while ((c = fgetc(in)) > 0) {
        ch = (char)c;
        /* write to child */
        rc = write(parent_to_child[1], &ch, 1);
        /* .... */
        /* read back from child */
        rc = read(child_to_parent[0], &ch, 1);
        /* .... */
        putchar(c);
    }

Come sono pigro per compilare / prova per voi, vorrei semplicemente ipotizzare che il genitore è bloccato nel read (). Perché dall'altra parte (bash nel processo figlio) non è garantita l'eco ogni indietro carattere scritto. O potrebbe anche decidere di stampare più di un carattere quanto il codice è in grado di gestire.

Nel caso si deve poll () per vedere se c'è qualcosa da leggere oppure no. O impostare il flag O_NONBLOCK sul child_to_parent [0] con fcntl (F_SETFL) e quando errno == EAGAIN, semplicemente saltare il ramo di lettura (). E ciclo mentre ci sono ancora caratteri da leggere.

.

Edit1 BTW ho completamente perso la parte: nella do_parent () loop di dover usare poll () su entrambi child_to_parent[0] e in, dal lato opposto potrebbe scrivere qualcosa (read () wouldn' t blocco) anche quando non lo fai write () qualsiasi carattere ad esso.

Altri suggerimenti

Grazie a te sembra ho ottenuto che sta funzionando.

Quindi, qui il codice viene aggiornato di do_parent:

void do_parent()
{
    int c;
    char ch;
    int rc;
    FILE *in;

    struct pollfd fds[2];
    int pol_ret;

    fds[0].fd = child_to_parent[0];

    close(child_to_parent[1]); /* we don't need to write to this pipe.  */
    close(parent_to_child[0]); /* we don't need to read from this pipe. */

    while (1)
    {   
        in = fopen("input.txt", "r");
        fds[1].fd = fileno(in);
        pol_ret = poll(fds, 2, 500);

        while ((c = fgetc(in)) > 0) {
            ch = (char)c;
            /* write to child */
            rc = write(parent_to_child[1], &ch, 1);
            if (rc == -1) {
                perror("child: write");
                close(child_to_parent[0]);
                close(parent_to_child[1]);
                exit(1);
            }
            /* read back from child */
            if (fds[0].revents & POLLIN)
            {
                rc = read(child_to_parent[0], &ch, 1);
                c = (int)ch;
                if (rc <= 0) {
                    perror("parent: read");
                    close(child_to_parent[0]);
                    close(parent_to_child[1]);
                    exit(1);
                }
                putchar(c);
            }
        }
        fclose(in);
    }
    close(child_to_parent[0]);
    close(parent_to_child[1]);
    exit(0);
}

Anche io ho aggiunto questo in do_child ():

dup2(parent_to_child[0], STDIN_FILENO);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top