IPC (межпроцессное взаимодействие) между python и java

Во-первых, небольшое объяснение, почему я задаю этот вопрос в первую очередь: я пишу программу на Python (с графическим интерфейсом wxPython), которая должна вызывать программу Java AWT из python и извлекать из нее данные. У меня есть рабочее решение для Windows. У меня также есть внутрипроцессное решение для OSX, пока я запускаю приложение Java без головы. К сожалению, нет разумного решения, которое я нашел для запуска обоих графических интерфейсов в одном и том же процессе в OSX, потому что и AWT, и WX оба хотят первый поток и не могут совместно использовать цикл сообщений wx.

То, что я хотел бы сделать, это запустить программу Java в отдельном процессе от моей программы Python и установить канал или очередь или что-то для передачи данных (в частности, байтовых массивов) назад и вперед.

Я был бы очень признателен за любые предложения или даже толчок в правильном направлении, так как у меня очень мало опыта работы с IPC.

7 ответов

Решение

Я пытался закодировать решение, используя каналы, но кажется, что они просто не подходят для отправки нескольких сообщений туда и обратно с прикрепленными потенциально большими данными. Скорее они кажутся идеальными для открытия программы в стиле "рабочий", которая запускается, отвечает и умирает.

Глядя на программирование сокетов, я нашел здесь фантастический ресурс: https://web.archive.org/web/20080913064702/http://www.prasannatech.net/2008/07/socket-programming-tutorial.html

В учебном пособии представлены TCP и UDP варианты простой программы чата, написанной на 4 языках. Я закончил тем, что использовал и изменил клиент TCP Java и сервер Python.

Это решение с открытым исходным кодом, которое Google использует для IPC между Java и Python. https://code.google.com/p/protobuf/

Рекомендуемые.

IPC с использованием subprocess из в питоне

Файл IPC.java здесь java-код получит номер и отправит его квадрат.

import java.util.Scanner;

public class IPC {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String data="";
        while(scanner.hasNext()){
            // Receive data from Python code 
            data = scanner.nextLine();

            // Process data (calculate square)
            int x = Integer.parseInt(data);
            int square = x*x;


            // Send data to python code
            System.out.println(square);
        }
        scanner.close();
    }
}

Файл IPC.py

import subprocess
subprocess.run(["javac", "IPC.java"])
proc = subprocess.Popen(["java", "IPC"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
for i in range(10):
    # Send to java code
    proc.stdin.write(b'%d\n' % i)
    proc.stdin.flush()
    proc.stdout.flush()

    # Receive data from java code
    output = proc.stdout.readline()
    print (output.rstrip())
proc.communicate()

Используйте subprocess.Popen, чтобы запустить процесс Java и установить каналы для связи с ним. Чтобы эффективно сериализовать и десериализовать данные не зависящим от языка, не зависящим от платформы, расширяемым способом, взгляните на буфер протоколов (предоставленный Jon Skeet!).

У меня была похожая ситуация, когда мне приходилось общаться между процессом Java и процессом Linux. Я использовал именованные каналы.

Попробуйте реализацию mkfifo() в python.

Межпроцессное взаимодействие между Python и Java



Реализация автономной, независимой от системы JRE в приложении Python.


Чтобы сделать приложение Python независимым от системы в целом, внутри приложения Python необходимо создать JRE. Это необходимо сделать, если требуется, чтобы приложение не зависело от системы и все было самодостаточно внутри приложения. Это полезно, если приложение в целом должно быть готово к запуску на любом компьютере пользователя без каких-либо дополнительных ресурсов и процедур при каждой установке.

Перейдите по адресу https://learn.microsoft.com/en-us/java/openjdk/download, загрузите JDK для желаемой аппаратной архитектуры и ОС и загрузите его в среду приложения Python. После этого поместите проект приложения Java целиком или.jarфайл, созданный из приложения Java в каталоге приложения Python.

Затем вы можете запустить приложение Java в приложении Python как подпроцесс.



Методы межпроцессного взаимодействия


Межпроцессное взаимодействие в реальном времени с использованием stdin , stout и stderr



,stdout , иstderrпотоки — это основные системы ввода-вывода, которые ядро ​​ОС использует для приложений и процессов. Изменяя поток этих потоков от дочернего процесса к ОС, от дочернего процесса к родительскому процессу, эти потоки будут пропускаться через родительский процесс, и родительский процесс будет иметь возможность выполнять операции ввода и вывода непосредственно с дочерним процессом.


[Код Java]

      public class Main {

    public static void main(String[] args)
    {
        // Send input over the "stdout" stream to the Python parent process
        System.out.println("Message from Java application");
        System.out.flush();

        // Read input over the "stdin" stream from the Python parent process
        Scanner s = new Scanner(System.in);
        String input = s.nextLine();
        s.close();

        // Send input over the "stdout" stream to the Python parent process
        System.out.println(input);
        System.out.flush();
    }
}

[Код Python]

      import subprocess

# Path to java.exe, in case the application contains a self-contained java environment, else just the "java" command
path_to_java_exe = "C:\\Users\\Teodor Mihail\\PycharmProjects\\Python_IPC\\jre\\bin\\java.exe"

# Command line argument that specifies the compiler what it should compile, in this case is a ".jar" file
java_exe_arguments = "-jar"

# The path to the file that the compiler will run and the runtime will execute, in this case it is the whole program compiled as a ".jar" file
java_jar_file_path = "C:\\Users\\Teodor Mihail\\PycharmProjects\\Python_IPC\\Java_I.P.C.jar"

# Global variable that holds the sub-process
process = None




def subprocess_startup():
    # Specify that the "process" variable is a reference to the global variable "process"
    global process

    # Open the process and redirect the "stdin", "stdout", and "stderr" streams from the sub-process to the OS to the Python process
    process = subprocess.Popen([path_to_java_exe, java_exe_arguments, java_jar_file_path], stdin=subprocess.PIPE,
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)


def subprocess_read_stdout():
    # Read the output sent by the Java application sub-process over the "stdout" stream
    received = process.stdout.readline()
    print(received)


def subprocess_write_stdin(data):
    # Write input to the Java application over the "stdin" stream
    process.stdin.write(data.encode("utf-8"))
    process.stdin.flush()


def main():
    subprocess_startup()

    # A loop can be implemented here for continuous read and write operations.
    # Both the read and write operation methods can be open on different threads
    # to perform continuous read and write operations executed in parallel


    subprocess_read_stdout()

    # Data to be written on the stdin stream must end in "\n" otherwise the Java
    # Scanner will lock. This will happen because the Scanner in Java is
    # scanning until a "\n" is found, otherwise it will wait indefinitely
    # until it will find a "\n" within the input stream.
    subprocess_write_stdin("Message from Python application\n")



    subprocess_read_stdout()


if __name__ == '__main__':
    main()

На каждомprocess.stdin.writeвызов метода, данные, отправленные дочернему процессу, должны завершаться символом новой строки ("\n"). Это необходимо сделать, поскольку сканер Java будет сканироватьstdinпоток ищет символ новой строки, и поскольку поток буферизован, это приведет к блокировке потока, в котором выполняется эта операция.



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