Soru popen okumak ve yazmak


Popen tarafından döndürülen bir dosya tanıtıcısını okumak ve yazmak mümkün mü? C ile kontrol etmek istediğim interaktif bir sürecim var. Popen ile bu mümkün değilse, bunun etrafında bir yolu var mı?


26
2018-05-30 01:27


Menşei


Olmalı, neden olmasın? - Dani
Değil. Borular tek yönlüdür. - R..
Kopyası stackoverflow.com/questions/3884103/... ? - Nemo


Cevaplar:


Daha önce de cevaplandığı gibi, popen tek yönde çalışıyor. Okumak ve yazmanız gerekirse, pip () ile bir boru oluşturabilir, fork () ile yeni bir süreç açabilir ve işlevleri çalıştırabilir ve daha sonra giriş ve çıkışlarını dup2 () ile yeniden yönlendirebilirsiniz. Her halükarda, popen üzerinde çalıştırmayı tercih ederim, çünkü süreç üzerinde size daha iyi bir kontrol sağlar (örn. Pidesini bilirsiniz)

DÜZENLENMİŞ:

Öneriler gibi, bir boru sadece bir yönde kullanılabilir. Bu nedenle okuma ve yazma için ayrı borular oluşturmalısınız. Daha önce yayınlanan örnek yanlış olduğundan, onu sildim ve yeni, doğru bir tane oluşturdum:

#include<unistd.h>
#include<sys/wait.h>
#include<sys/prctl.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>

int main(int argc, char** argv)
{
  pid_t pid = 0;
  int inpipefd[2];
  int outpipefd[2];
  char buf[256];
  char msg[256];
  int status;

  pipe(inpipefd);
  pipe(outpipefd);
  pid = fork();
  if (pid == 0)
  {
    // Child
    dup2(outpipefd[0], STDIN_FILENO);
    dup2(inpipefd[1], STDOUT_FILENO);
    dup2(inpipefd[1], STDERR_FILENO);

    //ask kernel to deliver SIGTERM in case the parent dies
    prctl(PR_SET_PDEATHSIG, SIGTERM);

    //replace tee with your process
    execl("/usr/bin/tee", "tee", (char*) NULL);
    // Nothing below this line should be executed by child process. If so, 
    // it means that the execl function wasn't successfull, so lets exit:
    exit(1);
  }
  // The code below will be executed only by parent. You can write and read
  // from the child using pipefd descriptors, and you can send signals to 
  // the process using its pid by kill() function. If the child process will
  // exit unexpectedly, the parent process will obtain SIGCHLD signal that
  // can be handled (e.g. you can respawn the child process).

  //close unused pipe ends
  close(outpipefd[0]);
  close(inpipefd[1]);

  // Now, you can write to outpipefd[1] and read from inpipefd[0] :  
  while(1)
  {
    printf("Enter message to send\n");
    scanf("%s", msg);
    if(strcmp(msg, "exit") == 0) break;

    write(outpipefd[1], msg, strlen(msg));
    read(inpipefd[0], buf, 256);

    printf("Received answer: %s\n", buf);
  }

  kill(pid, SIGKILL); //send SIGKILL signal to the child process
  waitpid(pid, &status, 0);
}

20
2018-05-30 05:28



Bu süreç 'stdout' sürecini stdin'e yazmaz mı? Potansiyel olarak sonsuz bir döngüye neden oluyor? Ben bir uzman değilim ama bunu araştırıyordum ve 2 boruya ihtiyacınız varmış gibi görünüyor. - Aktau
Yazma ve okuma ters çevrilir, yazılır (pipefd [1]), okunur (pipefd [0]) - Sherlock
pipe () tek yönlü bir veri kanalı oluşturur. Bu nedenle, iki boru oluşturmalısınız veya okunabilir ve yazılan veriler karışabilir. - Meixner
Bu kod kesinlikle yanlış. Pipefd'den okuyamazsınız [1] ve pipefd'e yazamazsınız [0]. Boru iki ucu olan TEK bir kanaldır. Bunu uygulamak için iki boruya ihtiyacınız var. - user2808671


Sebep popen() ve arkadaşlar çift yönlü iletişim sunmuyorlar, alt süreçte arabelleğe alınma nedeniyle kilitlenmeye eğilimli olacaklar. Tüm derme çatma boruları ve socketpair() Cevaplarda tartışılan çözümler aynı sorundan muzdariptir.

UNIX altında, çoğu komut bir satır okumak ve hemen standart bir tty ise, hemen onu işlemek ve yazdırmak için güvenilir olamaz. Bunun nedeni stdio arabelleklerinin varsayılan olarak kullanıcı alanında çıktıklarıdır. write() arabellek doluncaya veya stdio akışı kapatılıncaya kadar sistem çağrısı (genellikle program veya betik girişte EOF gördükten sonra çıkmak üzere). Böyle bir programın stdinine bir borudan yazıyorsanız ve şimdi bu programın stdout'undan (giriş borusunu kapatmadan) bir cevap beklerseniz, cevap stdio arabelleklerinde ve asla çıkmayacak - Bu bir kilitlenme.

Bazı çizgi odaklı programları kandırabilirsiniz (ör. grep) Onlarla konuşmak için bir sözde-kullanarak tamponlama değil; şuna baksana libexpect(3). Ancak genel durumda, her mesaj için farklı bir alt süreci yeniden çalıştırmanız gerekecek ve her mesajın sonunu bildirmek için EOF kullanılmasına izin verilmeli ve komutta (veya komutların boru hattı) yıkanması için tamponlar kullanılmalıdır. Açıkçası performans açısından iyi bir şey değil.

Bu sorun hakkında daha fazla bilgi için bkz. perlipc man sayfası (bu, Perl'deki iki yönlü borular içindir, ancak ana program için kullanılan dilden bağımsız olarak tamponlama hususları geçerlidir).


5
2018-04-25 13:38



Eğer sen read() ve write() ile dosya tanımlayıcılarını kontrol ettikten sonra poll(), Neden çıkmadığını göremiyorum. Yazmak için hala veri sahibi olduğunuz zaman bile okumak zorunda olduğunuz için yanınızda bir tamponlama gerektirmesi doğrudur, ancak bu bana bir problem gibi gelmiyor. - Pavel Šimerda
@ PavelŠimerda, verilerin bir alt tamponda değil, alt süreçteki 'kullanıcı alanı' olduğu için kilitlenecekti. - DomQ
Bu açıklamıyor ve güvenilir değil, cevabımı gör. - Pavel Šimerda
@ PavelŠimerda Alıntılarımı okumak için zaman ayırdınız mı? - DomQ


Popen2 olarak adlandırılan bir şey istiyorsun. İşte bir temel uygulama hata kontrolü olmadan.


4
2018-05-30 02:21





popen() boruyu sadece okuma veya yazma modunda açabilir, her ikisini de değil. Şuna baksana bu Bir geçici çözüm için iş parçacığı.


3
2018-05-30 01:30





kullanım forkpty (standart değil ama API çok güzel ve eğer sahip değilseniz, kendi uygulamanıza her zaman girebilirsiniz) ve exec Çocuk işleminde iletişim kurmak istediğiniz program.

Alternatif olarak, eğer tty semantiği sizin beğeninize değilse, forkpty ancak iki boruyu kullanarak, her iletişim yönü için bir tane veya socketpairBir harici soket üzerinden harici program ile iletişim kurar.


1
2018-05-30 01:32





Kullanamazsın popen iki yönlü borular kullanmak.

Aslında, bazı işletim sistemleri iki yönlü boruları desteklememektedir, bu durumda bir soket çifti (socketpair) bunu yapmanın tek yolu.


0
2018-05-30 01:31



İki yönlü borulara ihtiyacınız yok, sadece daha fazla boruya ihtiyacınız var (bir giriş, bir çıkış). - Ben Voigt
popen aslında bir FILE* ve bir boru değil. FILE* Çift yönlü borular mevcut değilse, dahili olarak iki boru kullanabilirsiniz. - Ajay Brahmakshatriya


Birinde netresolve backends Bir senaryo ile konuşuyorum ve bu yüzden onun için yazmalıyım stdin ve onun oku stdout. Aşağıdaki fonksiyon stdin ve stdout ile bir boruya yönlendirilmiş bir komut yürütür. Onu kullanabilir ve beğeninize göre uyarlayabilirsiniz.

static bool
start_subprocess(char *const command[], int *pid, int *infd, int *outfd)
{
    int p1[2], p2[2];

    if (!pid || !infd || !outfd)
        return false;

    if (pipe(p1) == -1)
        goto err_pipe1;
    if (pipe(p2) == -1)
        goto err_pipe2;
    if ((*pid = fork()) == -1)
        goto err_fork;

    if (*pid) {
        /* Parent process. */
        *infd = p1[1];
        *outfd = p2[0];
        close(p1[0]);
        close(p2[1]);
        return true;
    } else {
        /* Child process. */
        dup2(p1[0], 0);
        dup2(p2[1], 1);
        close(p1[0]);
        close(p1[1]);
        close(p2[0]);
        close(p2[1]);
        execvp(*command, command);
        /* Error occured. */
        fprintf(stderr, "error running %s: %s", *command, strerror(errno));
        abort();
    }

err_fork:
    close(p2[1]);
    close(p2[0]);
err_pipe2:
    close(p1[1]);
    close(p1[0]);
err_pipe1:
    return false;
}

https://github.com/crossdistro/netresolve/blob/master/backends/exec.c#L46

(Aynı kodu kullandım Popen () boru () + fork () gibi çift yönlü borular yapabilir mi?)


0
2018-02-23 17:18





popen benim için her iki yönde çalışır (okuma ve yazma) Ben kullanıyorum popen() her iki yönde boru ..

Çocuk süreçlerini okuma ve yazma stdin ve stdout popen tarafından döndürülen dosya tanıtıcısıyla (command, "w")

İyi çalışıyor gibi görünüyor.

Daha iyi bilmeden önce çalışacağını varsaydım ve öyle. Yukarıdaki mesajlara göre bu işe yaramaz .. Bu beni biraz endişelendiriyor.

raspbian (raspbery pi debian) üzerinde gcc


-1
2017-10-08 08:43