Кросс-платформенный двунаправленный IPC

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

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

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

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

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, будет в этой функции, и я смогу обойтись без того, чтобы все остальное работало таким же образом.

Есть идеи?

Спасибо!

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
1 499
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

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

В WIN32 НЕТ механизма fork (), хотя продукт Interix явно поддерживает его.

Chris K 28.05.2009 18:23

Как и Cygwin. Я знаю, что есть проблемы и трудности - отсюда и ласковые слова «которые достигают эффекта fork и exec».

Jonathan Leffler 28.05.2009 19:33
Ответ принят как подходящий

В 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

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