私はあなたがソケットではなく、共有メモリセマフォを使用してWindows上でこの動作を実現することができる方法の例を作成しました。これは同じことを成し遂げます。少なくとも1つのPythonスクリプトが実行されている限り、C++プログラムは動作し続けます。すべてのスクリプトが終了すると、特定のタイムアウト時間内にPythonスクリプトが起動しなくなると、C++プログラムは終了します。
ここでのコードのほとんどは、Pythonスクリプト(複数可)からのTCP接続を監視するスレッドを実行し、C++プログラム、になります。
ザ・Pythonスクリプトだけチェック/ Windowsプログラムを開始し、その後、スクリプトが終了するまで開いたままにされたソケットを開きます。
Windowsプログラムは、このようにPythonスクリプトが実行されているときを追跡し、ソケット接続と切断を検出しました。これらの例では
、Windowsプログラムは、「ConsoleApplication11.exe」と呼ばれるように起こります。私はポート1234と15秒のタイムアウトを使用しました。これらは、C++プログラムの19行目から21行目で変更できます。また、C++プログラムの終了をより即座にしたい場合は、client_monitor_thread()の最後にreturnの代わりにexit()を呼び出します。
これは役に立ちます。
のPythonスクリプト:
import socket
import time
import psutil
import os
# check if the C++ program is running, start it if not
cppProgramName = "ConsoleApplication11.exe"
progRunning = False
for pid in psutil.pids():
p = psutil.Process(pid)
if (cppProgramName in p.name()):
progRunning = True
if not progRunning:
os.startfile(cppProgramName)
time.sleep(5) # wait for c++ program to start
# open a socket to the C++ program to tell it we need it to keep running
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 1234))
# (MAIN PROGRAM)
time.sleep(3)
# (END OF MAIN PROGRAM)
# close the socket to the C++ program
s.close()
C++プログラム:
// ConsoleApplication11.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <set>
#include <chrono>
#include <thread>
#include <winsock2.h>
#include <Ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib") // link with Ws2_32.lib
namespace
{
const unsigned int commonPort = 1234; // must match Python app
const unsigned int noClientsTimeoutLimit = 15; // quit when no clients connected for this many seconds
bool clientMonitorRunning = true; // flag to show client monitor is running
void client_monitor_thread()
{
// start up winsock service version 2.2
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
std::cout << "WSAStartup() failed with error: " << iResult << std::endl;
clientMonitorRunning = false;
return;
}
// create a socket for listening for incoming connection requests.
SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket == INVALID_SOCKET)
{
std::cout << "socket() function failed with error: " << WSAGetLastError() << std::endl;
closesocket(listenSocket);
clientMonitorRunning = false;
return;
}
// sockaddr_in structure specifies the address family, IP address, and port for the socket
sockaddr_in service;
service.sin_family = AF_INET;
inet_pton(AF_INET, (PCSTR)"127.0.0.1", &(service.sin_addr));
service.sin_port = htons(commonPort);
if (SOCKET_ERROR == bind(listenSocket, (SOCKADDR *)& service, sizeof(service)))
{
std::cout << "bind function failed with error " << WSAGetLastError() << std::endl;
closesocket(listenSocket);
clientMonitorRunning = false;
return;
}
// Listen for incoming connection requests on the created socket
if (SOCKET_ERROR == listen(listenSocket, SOMAXCONN))
{
wprintf(L"listen function failed with error: %d\n", WSAGetLastError());
closesocket(listenSocket);
clientMonitorRunning = false;
return;
}
std::cout << "Listening on port " << commonPort << std::endl;
// mow monitor client connections
std::set<unsigned int> activefds;
int timeoutCounter = 0;
while (clientMonitorRunning)
{
// check for existing clients disconnected
if (0 != activefds.size())
{
std::set<unsigned int> disconnectedfds;
for (auto fd : activefds)
{
int flags = 0;
char buf[10];
int rv = recv(fd, buf, 10, flags);
if (0 == rv)
{
disconnectedfds.insert(fd);
}
}
for (auto fd : disconnectedfds)
{
activefds.erase(fd);
}
}
// are any clients connected? do we need to quit?
if (0 == activefds.size())
{
std::cout << "No clients - will exit in " << noClientsTimeoutLimit - timeoutCounter << " seconds" << std::endl;
++timeoutCounter;
if (timeoutCounter == noClientsTimeoutLimit)
{
for (auto fd : activefds)
{
closesocket(fd);
}
closesocket(listenSocket);
clientMonitorRunning = false;
return;
}
}
else
{
timeoutCounter = 0;
}
// check for activity on the listening socket
fd_set readfds;
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
FD_ZERO(&readfds);
FD_SET(listenSocket, &readfds);
switch (select(sizeof(readfds), &readfds, NULL, NULL, &timeout))
{
case 0: // timeout
{
break;
}
case SOCKET_ERROR:
{
std::cout << "listen failed with error: " << WSAGetLastError() << std::endl;
closesocket(listenSocket);
clientMonitorRunning = false;
return;
}
default:
{
if (FD_ISSET(listenSocket, &readfds))
{
// accept the connection.
SOCKET fd = accept(listenSocket, NULL, NULL);
if (fd == INVALID_SOCKET)
{
std::cout << "accept failed with error: " << WSAGetLastError() << std::endl;
closesocket(listenSocket);
clientMonitorRunning = false;
return;
}
else
{
unsigned long nonBlock = 1;
ioctlsocket(fd, FIONBIO, &nonBlock);
activefds.insert(fd);
}
}
break;
}
}
}
return;
}
}
int main()
{
// start the client monitor thread, which will run until no clients are connected
std::thread clientMonitor(client_monitor_thread);
// placeholder for doing the actual work in this program
// loop until the client monitor thread exits
while (clientMonitorRunning)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
// clean up
clientMonitor.join();
WSACleanup();
return 0;
}
あなたは[ 'mmap']を使用することができます(https://docs.python.org/3/library/mmap.html )モジュールを 'tagname'で置き換えます。 Windowsの共有メモリはセクションオブジェクトであり、他のいくつかのカーネルオブジェクトタイプ(デバイス、イベントなど)のようにオブジェクト名前空間に名前を付けることができます。 「share1234」などの名前は、現在のWindowsセッションのローカルです。すべてのセッションで名前にアクセスできるようにするには、 "Global \ share1234"を使用します。後者は、区切り記号としてバックスラッシュを使用しなければなりません。スラッシュはカーネル内の名前文字に過ぎないからです。 – eryksun
グローバル名を作成すると、これがどのように実装されているかによってパス区切りが使用されます。 Windows APIは、グローバル名(すべてのセッション)に '\ BaseNamedObjects'を、セッションにローカルな名前として' \ Sessions \ [セッション番号] \ BaseNamedObjects'を使います。ローカルのBNOには "グローバル"なシンボリックリンクがありますので、これは実際には '\ Sessions \ 1 \ BaseNamedObjects \ Global \ share1234' =>' \ BaseNamedObjects \ share1234'のように解決しています。 – eryksun