Envoyer sur stdin, récupérer stdout, d'un processus crée

Envoyer sur stdin, récupérer stdout, d'un processus crée - C - Programmation

Marsh Posté le 21-11-2004 à 11:38:36    

Bonjour.
 
J'aimerai savoir comment faire pour envoyer des données dans un processus créé, et comment récupérer sa sortie (sans arrêter le processus j'entends).
 
Il s'agit d'une application client/serveur, côté client, il demande la création d'un processus, ie: CreateProcess bc par exemple, le serveur doit alors créer le processus de son côté et renvoyer "OK pid" (ou identifiant quoi). A partir de là, le client peut envoyer des données à son processus "SendInput <identifiant du proc> les données", et quand il désirera voir la sortie standard du proc "GetOutput <identifiant>" qui affichera côté client toute la sortie déjà effectuée par le processus (le processus étant toujours en exécution).
 
La majeure partie a été réalisé, mais là, je bloque sur la gestion de l'entrée/sortie standard du processus. (il faudra d'ailleurs aussi que je puisse récup' le code de retour du processus si le client le désire).
 
J'ai essayé de forker + exec à la main, de dup[2], mais sans succès. Après, j'ai vu la fonction pipe(), mais avec le fork et autre dup, je m'emmèlais un peu, enfin, j'ai vu popen() qui a l'air sympathique (réalise tout) mais je me demande si elle convient pour ce que je veux faire. (comme un popen ne peut être que "r" ou "w" exclusivement, je devrais en créer alors deux, un "r" pour GetOutput, un "w" pour SendInput, mais je n'ai qu'un processus à exécuter :|)
 
Quelqu'un aurait une idée générale pour réaliser ceci ?
 
Merci.
 
Edit: Je précise que plusieurs processus peuvent être créés (d'où l'id distinct pour chaque).


Message édité par andOceans le 21-11-2004 à 11:58:24
Reply

Marsh Posté le 21-11-2004 à 11:38:36   

Reply

Marsh Posté le 21-11-2004 à 14:18:19    

si communication père-files -> pipe
sinon IPC classique : SHM, tube nommés, socket

Reply

Marsh Posté le 21-11-2004 à 14:40:25    

Et bien, avec les pipes, ça donne ça :
 

Code :
  1. typedef struct {
  2.   pid_t pid;
  3.   int rc;
  4.   int fd[2];
  5. } processinfo_t;
  6. #define IN  1
  7. #define OUT 0
  8. void send_input(pid_t pid, const char *input) {
  9.   ...
  10.   write(processes[index].fd[IN], input, strlen(input) + 1); 
  11. }
  12. char *get_output(pid_t pid) {
  13.   ...
  14.   read(processes[index].fd[OUT], buffer, sizeof buffer); 
  15.   return buffer;
  16. }
  17. pid_t create_process(const char *app) {
  18.     ...
  19.     proc = fork();
  20.     if (proc > 0) { return procinfo->pid = proc; }
  21.     if (proc == 0) {
  22.       if (execlp("tr", "tr", "[:upper:]", "[:lower:]", NULL) < 0)
  23. return 0;
  24.     }
  25.     ...
  26. }


 
Une sortie :
 


>> CreateProcess bla
## OK 3248
>> SendInput 3248 BlA
## OK
>> GetOutput 3248
## OK BlA <<<< je voudrais "OK bla"


 
Il manque l'étape du <je passe dans le processus>. Mais je n'arrive pas à savoir comment la mettre. J'ai essayé des dup2(foo.fd[IN], STDIN_FILENO) mais je n'ai jamais le résultat escompté.

Reply

Marsh Posté le 03-12-2004 à 00:17:44    

Alors alors.. j'ai crée en fait deux tubes (in, et out), chacun unidirectionnel, un pour père -> fils, l'autre, fils -> père. Dans la création du processus côté serveur, j'ai maintenant :
 

Code :
  1. if (proc == 0) {
  2.       /* L'envoi sur stdin fonctionne */
  3.       dup2(procinfo->in[READ], STDIN_FILENO);
  4.       close(procinfo->in[READ]);
  5.       close(procinfo->in[WRITE]);
  6.       /* Ne fonctionne pas !! =(
  7.       dup2(procinfo->out[WRITE], STDOUT_FILENO);
  8.       close(procinfo->out[READ]);
  9.       close(procinfo->out[WRITE]); */
  10.       execlp("tr", "tr", "[:upper:]", "[:lower:]", NULL);
  11.       return 0;
  12. }


La redirection du stdout ne fonctionne toujours pas. Quand j'appelle GetOutput, qui exécute ## n = read(processes[index].out[READ], buffer, sizeof buffer); ##, le client bloque. Pourtant, il a dû y avoir une sortie car auparavant, j'envoie quelque chose via un SendInput ... (celui ci fonctionne, j'ai testé en commentant le "ne fonctionne pas", et côté serveur, ca affiche bien le texte passé par le client en lower)
 
Help =(

Reply

Marsh Posté le 04-12-2004 à 13:30:58    

Le plus bizarre, c'est que si je mets ça :  

Code :
  1. if (proc == 0) {
  2.       dup2(procinfo->in[READ], STDIN_FILENO);
  3.       close(procinfo->in[READ]);
  4.       close(procinfo->in[WRITE]);
  5.       dup2(procinfo->out[WRITE], STDOUT_FILENO);
  6.      
  7.       /* les deux agissent pareillement et fonctionnent */
  8.       write(STDOUT_FILENO, "foobar", strlen("foobar" ) + 1);
  9.       write(procinfo->out[WRITE], "foobar", strlen("foobar" ) + 1);
  10.       execlp("tr", "tr", "[:upper:]", "[:lower:]", NULL);
  11.       return 0;
  12.     }


Les deux writes fonctionnent ! (ie: je peux récupérer "foobarfoobar" quand je fais un GetOutput) Logiquement, tr écrivant sur STDOUT_FILENO aussi, devrait remplir le pipe, or, ça bloque, donc je suppose qu'il ne le remplit pas.. (close on exec est bien à 0 pour les descripteurs)

Reply

Marsh Posté le 04-12-2004 à 16:03:54    

En fait, il s'agit d'un problème de flush.

Code :
  1. if (proc == 0) {
  2.       dup2(procinfo->in[READ], STDIN_FILENO);
  3.       close(procinfo->in[READ]);
  4.       close(procinfo->in[WRITE]);
  5.       dup2(procinfo->out[WRITE], STDOUT_FILENO);
  6.       close(procinfo->out[READ]);
  7.       close(procinfo->out[WRITE]);
  8.       printf("Blablabla" );
  9.       /*fflush(stdout);*/
  10.       execlp("tr", "tr", "[:upper:]", "[:lower:]", NULL);
  11.       return 0;
  12.     }


Sans le fflush, si je crée un processus et que je lis directement sa sortie, le client bloque; avec le fflush, je récupère "Blablabla". Il faudrait donc que le stdout du processus execlp soit fflushé à chaque entrée, comme stderr je crois. (sans pour autant les fusionner avec des dups, j'aimerai avoir le stderr à part également si c'est possible :\)
 
J'ai été voir du côté de fnctl, mais rien ne concernant mon problème amha. Comment faire ?

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed