2008-10-31 4 views
2

У меня есть проект, который, как я думал, будет относительно легким, но оказывается более больным, чем я надеялся. Во-первых, большая часть кода, с которым я взаимодействую, - это устаревший код, который я не контролирую, поэтому я не могу делать большие изменения парадигмы.Crossplatform двунаправленный IPC

Вот упрощенное объяснение того, что мне нужно сделать. Скажем, у меня есть большое количество простых программ, которые читаются из stdin и записываются в stdout. (Это я не могу трогать). В принципе, вход в stdin - это команда типа «Установить температуру до 100» или что-то в этом роде. И выход - это событие «Температура установлена ​​на 100» или «Температура упала ниже заданного значения».

Что бы я хотел сделать, это написать приложение, которое может запускать кучу этих простых программ, следить за событиями и затем при необходимости отправлять команды им. Мой первоначальный план состоял в том, что-то вроде popen, но мне нужно использовать двунаправленный popen, чтобы получить как чтение, так и запись. Я взломал что-то вместе, что я называю popen2, где я передаю ему команду для запуска, и два FILE *, которые заполняются потоком чтения и записи. Тогда все, что мне нужно сделать, это написать простой цикл, который читает из каждого из stdouts из каждого из процессов, выполняет ли логику, в которой он нуждается, а затем записывает команды обратно в соответствующий процесс.

Вот некоторые псевдокод

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); 
} 

Настоящая программа является более сложной, когда он заглядывает в потоке, чтобы увидеть, если что-то ждет, если нет, то он пропустит этот процесс, также, если это не нужно отправьте команду на определенный процесс, которого нет. Но этот код дает основную идею.

Теперь это отлично работает на моей коробке UNIX и даже довольно хорошо на коробке Windows XP с cygwin. Однако теперь мне нужно заставить его работать на Win32 изначально.

Жесткая часть заключается в том, что мой popen2 использует fork() и execl() для запуска процесса и назначения потоков для stdin и stdout дочерних процессов. Есть ли чистый способ сделать это в окнах? В принципе, я хотел бы создать popen2, который работает в окнах так же, как моя версия unix. Таким образом, единственный конкретный код для Windows будет в этой функции, и я мог бы уйти со всем остальным, работающим одинаково.

Любые идеи?

Спасибо!

ответ

5

В Windows вы сначала вызываете CreatePipe (аналогично pipe (2)), а затем CreateProcess. Трюк здесь заключается в том, что CreateProcess имеет параметр, в котором вы можете передать stdin, stdout, stderr только что созданного процесса.

Обратите внимание, что когда вы используете stdio, вам нужно сделать fdopen для создания файлового объекта после этого, который ожидает номера файлов. В Microsoft CRT номера файлов отличаются от дескрипторов файлов ОС. Поэтому, чтобы вернуть другой конец CreatePipe для вызывающего, вам сначала нужно _open_osfhandle, чтобы получить номер файла CRT, а затем fdopen.

Если вы хотите увидеть рабочий код, проверить _PyPopen в

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

0

Я думаю, что вы очень хорошо начали свою проблему, используя функцию popen2(), чтобы абстрагироваться от кросс-платформенных проблем. Я ожидал прийти и предложить «сокеты», но я уверен, что это не имеет значения после прочтения вопроса. Вы можете использовать сокеты вместо труб - он будет скрыт в функции popen2().

Я на 99% уверен, что вы можете реализовать требуемые функции в Windows, используя Windows API. То, что я не могу сделать, это надежно направить вас на правильные функции. Тем не менее, вы должны знать, что Microsoft имеет большинство доступных API-интерфейсов POSIX, но имя имеет префикс «_». Существуют также собственные вызовы API, которые обеспечивают эффект fork и exec.

Ваши комментарии предполагают, что вы знаете о проблемах с доступностью данных и возможных взаимоблокировках - будьте осторожны.

+0

Там нет вилки() механизма, доступного в WIN32, хотя продукт Interix, видимо, не поддерживает его. – 2009-05-28 14:23:48

+0

Так же и Cygwin. Я знаю, что есть проблемы и трудности - следовательно, ласковые слова, которые достигают эффекта вилки и exec. – 2009-05-28 15:33:28