Вопрос

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

Вот упрощенное объяснение того, что мне нужно сделать:Допустим, у меня есть большое количество простых программ, которые считывают данные из stdin и записывают в стандартный вывод.(К ним я не могу прикоснуться).По сути, ввод в stdin - это команда типа "Установить температуру на 100" или что-то в этом роде.И результатом является событие "Температура была установлена на 100" или "Температура упала ниже заданного значения".

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

Вот какой-то псевдокод

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 дочерним процессам.Есть ли чистый способ, которым я могу сделать это в Windows?По сути, я хотел бы создать popen2, который работает в Windows так же, как моя версия unix.Таким образом, единственный специфичный для Windows код был бы в этой функции, и мне могло бы сойти с рук все остальное, работающее таким же образом.

Есть какие-нибудь идеи?

Спасибо!

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top