Steuern Sie andere Programme von Python aus (Kommunikation zwischen Python ⇔ exe)

1. Zweck

Der Zweck besteht darin, andere Programme in Python auszuführen. Insbesondere habe ich mich gefragt, ob ich das in C veröffentlichte SDK in Kombination mit Python verwenden könnte.

2. Try & Error

2.1 Wenn es so gesteuert werden kann, wie es ist, durch den Python-Unterprozess

Ich habe dies übernommen, weil es möglich ist, andere ausführbare Programme von Python aus unter Verwendung des Unterprozesses des Python-Moduls auszuführen. Die Kommunikation mit anderen Prozessen umfasst eine prozessübergreifende Kommunikationsmethode namens PIPE, die sich anscheinend schnell erledigen lässt. Tatsächlich funktioniert es gut mit den folgenden Kombinationen von Python (Steuerung) und C (laufendes Programm).

OK.cpp


#include <stdio.h>

#define MAX_BUFFER 256

int main()
{
    char buf[MAX_BUFFER];

    fgets(buf, MAX_BUFFER, stdin);
    printf("your input is :%s", buf);

    return 0;
}

control.py


import subprocess as sp

if __name__ == "__main__":

    #Starten Sie die exe-Datei als Prozess
    #Verbinden Sie stdin und stdout als PIPE mit diesem Python
    cmd = ".\\OK.exe"
    p = sp.Popen(cmd, stdin=sp.PIPE, stdout=sp.PIPE)

    #Senden Sie Anweisungen an eine Instanz von Popen mit kommunizieren
    #Der Rückgabewert ist(stdout, stderr)Wegen des Taple von
    #Weil b vor der Zeichenfolge in Byte konvertiert wird
    out, err = p.communicate(input=b"Hello World")

    print(out)
    exit()

(Kompilieren Sie OK.cpp und legen Sie es als OK.exe im selben Ordner wie control.py unten ab.)

2.2 Wenn es nicht so gesteuert werden kann wie mit dem Python-Unterprozess (ich war süchtig danach)

Das SDK, mit dem ich den geänderten Status durch die Eingabe von stdin behandeln wollte, erforderte jedoch viele Eingaben. In diesem Fall wird der Vorgang am Kommunikationsteil gestoppt, selbst wenn Sie dieselbe control.py wie zuvor verwenden. Ein solches C-Programm ist beispielsweise NG.

NG.cpp


#include <stdio.h>
#include <string.h>

#define MAX_BUFFER 256

int main()
{
    char buf[MAX_BUFFER], *ret;
    //Empfangen Sie weiter, bis die Eingabezeichenfolge ein Endzeichen enthält
    while(1)
    {
        fgets(buf, MAX_BUFFER, stdin);
        printf("your input is :%s", buf);
        //Bestimmen Sie, ob die Eingabezeichenfolge ein Ende hat
        ret = strstr(buf, "end");
        //Wenn nicht, wird NULL in ret zurückgegeben, sodass die while-Anweisung beendet wird.
        if(ret!=NULL)
        {
            break;
        }
    }
    return 0;
}

Ich konnte auf der Python-Seite keine Implementierung finden, um dies zu lösen. Diesmal habe ich sie mit der Implementierung auf der C-Seite gelöst. Ein Beispiel für die Implementierung auf der C-Seite ist unten dargestellt. Wenn jedoch jemand weiß, wie dies auf der Python-Seite zu tun ist, würde ich es begrüßen, wenn Sie es mir sagen könnten. (Ich fand, dass pyexpect eine ziemlich gute Linie zu sein scheint, also habe ich es tatsächlich versucht, aber ich habe aufgegeben, weil ich nicht die volle Funktionalität nutzen konnte, es sei denn, es war Linux. Wenn ich es unter Linux mache, kann es etwas weniger problematisch sein. nicht)

3. Angenommene Methode: Socket-Kommunikation

Dieses Mal haben wir die TCP-Server / Client-Kommunikation übernommen, um Befehle zu empfangen und den Client-Prozess jedes Mal auf der Python-Seite zu starten. Ein Beispiel ist unten gezeigt.

main.cpp


#include "stdafx.h"

char *getCharTCP(char*);

int main()
{
    char buf[DEFAULT_BUFLEN];
    char *ret;
    //Empfangen Sie weiter, bis die Eingabezeichenfolge ein Endzeichen enthält
    while(1)
    {
        //fgets(buf, DEFAULT_BUFLEN, stdin);
        printf("waiting new input :\n");
        ret = getCharTCP(buf);
        printf("your input is :%s", buf);
        //Bestimmen Sie, ob die Eingabezeichenfolge ein Ende hat
        ret = strstr(buf, "end");
        //Wenn nicht, wird NULL in ret zurückgegeben, sodass die while-Anweisung beendet wird.
        if(ret!=NULL)
        {
            break;
        }
    }
    return 0;
}

getCharTCP.cpp


#include "stdafx.h"

char *getCharTCP(char *out)
{
    WSADATA wsaData;
    int iResult, i;

    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET ClientSocket = INVALID_SOCKET;

    struct addrinfo *result = NULL;
    struct addrinfo hints;

    int iSendResult;
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;
    char errorcode[DEFAULT_BUFLEN];
    strcpy(errorcode, "error");

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return errorcode;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return errorcode;
    }

    // Create a SOCKET for connecting to server
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return errorcode;
    }

    // Setup the TCP listening socket
    iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return errorcode;
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return errorcode;
    }

    // Accept a client socket
    ClientSocket = accept(ListenSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return errorcode;
    }

    // No longer need server socket
    closesocket(ListenSocket);

    // Receive until the peer shuts down the connection
    do {

        iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0) {
            printf("Bytes received: %d\n", iResult);

            // Echo the buffer back to the sender
            iSendResult = send(ClientSocket, recvbuf, iResult, 0);
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed with error: %d\n", WSAGetLastError());
                closesocket(ClientSocket);
                WSACleanup();
                return errorcode;
            }
            printf("Bytes sent: %d\n", iSendResult);
        }
        else if (iResult == 0)
            printf("Connection closing...\n");
        else {
            printf("recv failed with error: %d\n", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup();
            return errorcode;
        }

    } while (iResult > 0);

    // shutdown the connection since we're done
    iResult = shutdown(ClientSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return errorcode;
    }

    // cleanup
    closesocket(ClientSocket);
    WSACleanup();
    for (i = strlen(recvbuf) - 1; i >= 0; i--)
    {
        strncpy(out, recvbuf, i + 1);
        out[i + 1] = '\0';
        break;
    }
    printf("receive end\n");
    return out;
}

stdafx.cpp


#include "stdafx.h"

stdafx.h


#pragma once
//Deaktivieren Sie Visual Studio-Warnungen
#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <string.h>



//include für getCharTCP
#undef UNICODE

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>

// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

main.cpp


#include "stdafx.h"


int main(int argc, char **argv)
{
    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
        *ptr = NULL,
        hints;
    char sendbuf[DEFAULT_BUFLEN];
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;

    printf("please write letters to control program :\n");
    fgets(sendbuf, DEFAULT_BUFLEN, stdin);

    // Validate the parameters
    if (argc != 2) {
        printf("usage: %s server-name\n", argv[0]);
        return 1;
    }

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Attempt to connect to an address until one succeeds
    for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("socket failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return 1;
        }

        // Connect to server.
        iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0)
            printf("Bytes received: %d\n", iResult);
        else if (iResult == 0)
            printf("Connection closed\n");
        else
            printf("recv failed with error: %d\n", WSAGetLastError());

    } while (iResult > 0);

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}

stdafx.h


#pragma once

#include <stdio.h>

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>


// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")


#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

(Ich habe das kompilierte Serverprogramm und das Clientprogramm im selben Ordner wie Python abgelegt.)

control.py


import subprocess as sp

if __name__ == "__main__":

    #Starten Sie die exe-Datei auf der Serverseite
    #Diese Datei ist das SDK
    cmd = ".\\server.exe"
    pserve = sp.Popen(cmd)

    #Clientseitiges Programm
    cmd = ".\\client.exe localhost"
    pclient = sp.Popen(cmd, stdin=sp.PIPE, stdout=sp.PIPE)
    out, err = pclient.communicate(input=b"Hello World 1st\n")
    pclient.kill()
    #Sie müssen jedes Mal eine Instanz starten, wenn Sie einen Befehl senden
    #Ich denke, es gibt eine bessere Umsetzung
    cmd = ".\\client.exe localhost"
    pclient = sp.Popen(cmd, stdin=sp.PIPE, stdout=sp.PIPE)
    out, err = pclient.communicate(input=b"Hello World 2nd\n")
    pclient.kill()
    exit()

4. Verschiedene Gefühle

Ich fing an zu denken, dass das Python-Modul sofort damit umgehen kann, aber ich war unerwartet süchtig danach, also schrieb ich es auf. Ich bin der Meinung, dass es eine bessere Lösung gibt (z. B. die Kommunikation zwischen Prozessen mit PIPE), sodass ich möglicherweise die Gelegenheit nutzen kann, weitere Untersuchungen durchzuführen. Da wir jedoch die TCP-Kommunikation implementiert haben, war es meiner Meinung nach ein guter Teil, dass sie von anderen PCs als Nebenprodukt ausgeführt werden konnte. Möglicherweise gibt es eine andere gute Steuerungsmethode, die das Python-Socket-Modul verwendet.

a1. Umwelt

OS:Win10 IDE: Visual Studio 2017 (sowohl C als auch Python wurden in VS2017 erstellt) Python : Anaconda 5.0.1

a2. URL der Referenzsite

Python-Beamter: Unterprozess [Achtung], wenn Sie eine Zeichenfolge in einer Funktion zurückgeben möchten (https://fa11enprince.hatenablog.com/entry/2014/06/10/023712) Beispiel für die Implementierung von Winsock2 (TCP-Kommunikation): Erste Schritte mit Winsock2

Recommended Posts

Steuern Sie andere Programme von Python aus (Kommunikation zwischen Python ⇔ exe)
Steuern Sie andere Programme von Python aus (Kommunikation zwischen Python ⇔ exe)
Prozessübergreifende Kommunikation zwischen Ruby und Python (POSIX-Nachrichtenwarteschlange)
Die I2C-Kommunikation erfolgt durch Steuerung der seriellen Kommunikation mit Python (über ein USBGPIO8-Gerät).
Serielle Kommunikationssteuerung mit Python- und SPI-Kommunikation (mit USBGPIO8-Gerät)
Unterschied zwischen Ruby und Python Split
Unterschied zwischen list () und [] in Python
Unterschied zwischen == und ist in Python
Python, Ausbeute, Rückkehr und manchmal Ausbeute von
Lesen und verwenden Sie Python-Dateien aus Python
Studie aus Python Hour2: Steueranweisung
Zusammenarbeit zwischen Python-Modul und API
Unterschied zwischen Python, Stftime und Strptime
Über Python, aus und importieren, als
Unterschied zwischen der Python2-Serie und der Python3-Serie dict.keys ()
Python 3-Socket-Modul und Socket-Kommunikationsfluss
[Python] Unterschied zwischen Funktion und Methode
Python - Unterschied zwischen exec und eval
[Python] Unterschied zwischen randrange () und randint ()
[Python] Unterschied zwischen sortiert und sortiert (Colaboratory)
Kommunizieren Sie mit gRPC zwischen Elixir und Python
Unterschied in der Authentizität zwischen Python und JavaScript
Von Python bis zur Verwendung von MeCab (und CaboCha)
Unterschiede zwischen Ruby und Python im Umfang
Socket-Kommunikation und Multithread-Verarbeitung durch Python
Unterschied zwischen Anweisungen (Anweisungen) und Ausdrücken (Ausdrücken) in Python
Unterschiede zwischen Python- und Java-Syntax
Unterschiede in der Beziehung zwischen PHP und Python schließlich und beenden
Unterschied zwischen @classmethod und @staticmethod in Python
Unterschied zwischen Anhängen und + = in der Python-Liste
Unterschied zwischen nicht lokal und global in Python
[Python] Unterschied zwischen Klassenmethode und statischer Methode
Portieren und Ändern des Doublet-Solvers von Python2 auf Python3.
[Anfänger] Python installieren und Programme ausführen (Windows)
[Python3] Wechseln Sie zwischen Shift_JIS, UTF-8 und ASCII
[Python Iroha] Unterschied zwischen Liste und Tupel
Socket-Kommunikation in C-Sprache und Python
[Python] Unterschied zwischen Rand- und Randn-Ausgabe
Unterschiede in der Multithread-Verarbeitung zwischen Python und Jython
Unterschied zwischen Ruby und Python (grundlegende Syntax)
Korrespondenz zwischen den in Python integrierten Funktionen und Rust
Kommunikation verschlüsselter Daten zwischen Python und C #
Studie aus Python Lesen und Schreiben von Hour9-Dateien
Die Antwort von "1/2" unterscheidet sich zwischen Python2 und 3
Unterschied zwischen Variablen und Selbst. Variablen in der [Python] -Klasse
[Python] Lesen von Daten aus CIFAR-10 und CIFAR-100
[Python] Finde Koordinaten aus zwei Winkeln und Entfernungen
[Python] Konvertierungsnotiz zwischen Zeitdaten und numerischen Daten
Über den Unterschied zwischen "==" und "is" in Python
Python-Handspiel (Interoperation zwischen CSV und PostgreSQL)
Laden Sie den Befehl von yml mit Python und führen Sie ihn aus
[Python] Kapitel 02-01 Grundlagen von Python-Programmen (Operationen und Variablen)
Verknüpfung von PHP und Python von Grund auf auf Laravel
Lassen Sie uns EV3-Motoren und -Sensoren mit Python steuern
Serielle Kommunikation zwischen Raspberry pi - Arduino Uno (Python)