2008-10-31 6 views
2

J'ai un projet que je pensais être relativement facile, mais qui s'avère être plus douloureux que ce que j'avais espéré. Tout d'abord, la plupart du code avec lequel j'interagis est un code hérité que je n'ai pas le contrôle, donc je ne peux pas faire de grands changements de paradigme.Crossplatform Bidirectionnel IPC

Voici une explication simplifiée de ce que je dois faire: Disons que j'ai un grand nombre de programmes simples qui lisent depuis stdin et écrivent sur stdout. (Ceux-ci je ne peux pas toucher). Fondamentalement, l'entrée à stdin est une commande comme "Définir la température à 100" ou quelque chose comme ça. Et la sortie est un événement "La température a été réglée sur 100" ou "La température est tombée en dessous du point de consigne". Ce que je voudrais faire est d'écrire une application qui peut démarrer un tas de ces programmes simples, surveiller les événements et leur envoyer des commandes si nécessaire. Mon plan initial était quelque chose comme popen, mais j'ai besoin d'un pop-rate bidrectional pour lire et écrire des tuyaux. J'ai piraté quelque chose ensemble que j'appelle popen2 où je lui passe la commande à exécuter et deux fichiers * qui sont remplis avec le flux de lecture et d'écriture. Ensuite, tout ce que je dois faire est d'écrire une simple boucle qui lit à partir de chacune des sorties stdouts de chacun des processus, fait la logique dont il a besoin, puis écrit les commandes dans le processus approprié.

Voici quelques pseudocode

FILE *p1read, *p1write; 
FILE *p2read, *p2write; 
FILE *p3read, *p3write; 

//start each command, attach to stdin and stdout 
popen2("process1",&p1read,&p1write); 
popen2("process2",&p2read,&p2write); 
popen2("process3",&p3read,&p3write); 

while (1) 
{ 
    //read status from each process 
    char status1[1024]; 
    char status2[1024]; 
    char status3[1024]; 
    fread(status1,1024,p1read); 
    fread(status2,1024,p2read); 
    fread(status3,1024,p3read); 

    char command1[1024]; 
    char command2[1024]; 
    char command3[1024]; 
    //do some logic here 

    //write command back to each process 
    fwrite(command1,p1write); 
    fwrite(command2,p2write); 
    fwrite(command3,p3write); 
} 

Le programme réel est plus complexe où il jette un œil dans le courant de voir si quelque chose est en attente, sinon, il va sauter ce processus, même si elle n'a pas besoin de envoyer une commande à un certain processus, il ne le fait pas. Mais ce code donne l'idée de base.

Maintenant, cela fonctionne très bien sur mon boîtier UNIX et même très bien sur une boîte Windows XP avec cygwin. Cependant, maintenant je dois l'obtenir pour fonctionner sur Win32 nativement.

Le plus dur est que mon popen2 utilise fork() et execl() pour démarrer le processus et assigner les flux à stdin et stdout des processus fils. Y a-t-il un moyen propre de le faire dans Windows? Fondamentalement, je voudrais créer un popen2 qui fonctionne dans Windows de la même manière que ma version unix. De cette façon, le seul code spécifique à Windows serait dans cette fonction et je pourrais partir avec tout le reste fonctionnant de la même manière.

Des idées?

Merci!

Répondre

5

Sous Windows, vous appelez d'abord CreatePipe (similaire à pipe (2)), puis CreateProcess. L'astuce ici est que CreateProcess a un paramètre où vous pouvez passer stdin, stdout, stderr du processus nouvellement créé.

Notez que lorsque vous utilisez stdio, vous devez faire fdopen pour créer l'objet fichier par la suite, ce qui attend des numéros de fichiers. Dans Microsoft CRT, les numéros de fichier sont différents des handles de fichiers du système d'exploitation. Donc, pour renvoyer l'autre extrémité de CreatePipe à l'appelant, vous devez d'abord _open_osfhandle pour obtenir un numéro de fichier CRT, puis fdopen dessus.

Si vous voulez voir le code de travail, consultez _PyPopen dans

http://svn.python.org/view/python/trunk/Modules/posixmodule.c?view=markup

+0

Merci Martin, c'est exactement ce dont j'avais besoin. – miked

0

Je pense que vous avez fait un très bon début à votre problème en utilisant la fonction popen2() pour éliminer les problèmes multiplateformes. Je m'attendais à venir proposer des «sockets», mais je suis sûr que ce n'est pas pertinent après avoir lu la question. Vous pourriez utiliser des sockets au lieu de pipes - il serait caché dans la fonction popen2().

Je suis sûr à 99% que vous pouvez implémenter la fonctionnalité requise sous Windows, en utilisant les API Windows. Ce que je ne peux pas faire, c'est pointer vers les bonnes fonctions de manière fiable. Cependant, vous devez savoir que Microsoft a la plupart des appels API POSIX disponibles, mais le nom est précédé de '_'. Il existe également des appels d'API natifs qui atteignent les effets fork et exec.

Vos commentaires suggèrent que vous êtes conscient des problèmes de disponibilité des données et d'éventuels blocages - soyez prudent.

+0

Il n'y a aucun mécanisme fork() disponible dans WIN32, bien que le produit Interix ne semble soutenir. –

+0

Tout comme Cygwin. Je sais qu'il y a des problèmes et des difficultés - d'où les mots weasel «qui obtiennent les effets de fork et exec». –

Questions connexes