Sorry for the lousy title, "InterProcess Communication" was too long
Basically, I'm looking to use the native _winapi
and msvcrt
modules to launch an integrated python interpreter and communicate with it over pipes
I can't find anything on Google or DDG, and I've been searching for days, but nobody uses these modules for some reason...
I already have the foundation with a 1-way Parent->Child pipe that works, but it's giving me a few issues:
1: I can't seem to get a 2nd Child->Parent pipe to run without the program hanging
2: the output of the subprocess only prints after the main process is closed (tbh though I rather want the main process to actively print through subprocess feedback, even if it's delayed a few ns)
Note that the code came from the CPU-heavy multiprocessing module.
(I just reduced the processing, so this code wastes MUCH less CPU cycles)
# -*- coding: utf-8 -*-
from _winapi import CreatePipe, CreateProcess, CloseHandle
from msvcrt import open_osfhandle
import _winapi, msvcrt
from nt import getpid
# this is just a mock-up path to a local interpreter, since __file__ doesn't include the drive letter on wine
CWD = 'Z:%s'%__file__.replace('test.py','').replace('\\','/')
exec_path = '%sapp/'%CWD
executable = '%spython.exe'%exec_path
rhandle, whandle = CreatePipe(None, 0) # Parent to Child
prog = '''
from _winapi import OpenProcess, DuplicateHandle, GetCurrentProcess, CloseHandle
from _winapi import PROCESS_DUP_HANDLE, DUPLICATE_SAME_ACCESS, DUPLICATE_CLOSE_SOURCE
from msvcrt import open_osfhandle
import sys
sys.path = ['.\\DLLs','%s'] # because -I doesn't "Isolate" as well as it's supposed to, and we still have environment paths here.
source_process_handle = OpenProcess(PROCESS_DUP_HANDLE, False, %s)
try:
handle = DuplicateHandle( source_process_handle, %s, GetCurrentProcess(), 0, False, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)
from_parent = open( open_osfhandle( handle, 0 ), 'rb', closefd=True ) # not using `with` because I intend to open a 2nd pipe to write to
exec(from_parent.read())
from_parent.close()
sys.exit(0)
finally:
CloseHandle(source_process_handle)'''%(exec_path, getpid(), rhandle)
cmd = '%s -I -S -c "%s" --multiprocessing-fork'%(executable, prog)
to_child = open( open_osfhandle( whandle, 0 ), 'wb', closefd=True ) # not using `with` because I intend to open a 2nd pipe to read from
# start process
try:
subprocess_handle, thread_handle, pid, tid = CreateProcess( executable, cmd, None, None, False, 0, None, None, None)
CloseHandle(thread_handle)
except:
CloseHandle(rhandle)
raise
# send information to child
to_child.write(b'print("success!")')
for i in range(10000000): i+i+1 # give the subprocess enough time to complete
input('Press Enter to Exit...\n\n')
CloseHandle(subprocess_handle)
to_child.close()
Is there any way I can introduce a 2nd pipe to have proper interprocess communication??
EDIT:
btw, to those looking to use this as an example, I highly recommend you NOT send raw python code through the pipe like I'm doing here with to_child.write(b'print("success!")')
What I'm doing is for testing purposes only, and should not be used in practical cases as it's extremely insecure!
the multiprocessing
module uses the pickle
module, but that's a joke because you can easily get the authstring to unpickle the pipe...
see this image:
https://lh3.googleusercontent.com/R8vYH1reL4GF4KTc2GrO88CsMrIVshMhZVTmYOG5naZAmhDH-NACHSB7XOIzriFrNi8YiyD4ic1crLFV5sRu32ELSTw-gU4O-DVnm8H0wtmZAvzmDM5qhnmR5klDfDIxIy5aNgYWG-7vVHq9uTMZp-uRLAdYdzSEs_urbOLB6tfiDFbelCSpPXdiH10xs9bj_EnCIjTrcQS06qPtNSiZR1BvmruxEd_24qaqcQODtiBCPB0MPxD3G_-73xGFk3QRqYr0JJpgNSZk7eaVRmED3QooxY245k9jv_g-xeiRvTGqVMWGbQMDzDjsiRLOFdB4l42370Gf-m9rWTNISfuVA0H_6FoZxdrYh6MzX8tz3j6bztHc51h_PLyGHaWlk70JOsXcvG5OF-3TJridaUTldwbyqNUTmz-sPFUOghPdzmYc5WBocNzaiONiHcfCVsDTJOV3dYWKii-qs_aroQKE3ZpdkcjGuw2t0VCuDvrN96ZtCO1YYbRCTKi-97wVUFXS26v9NeikAVCiTazAwdyTr98byg6WORCel6dZ2cZaAgG6vHQCr7OpLKhJpUQ3lNmmzTcNFpPW1m-MljOn1bFotn70Fuz2hs0p4M4LxKzWTI-0ps6-y5uvYFms6DUpLrQ77RMlUqHDHuNZtFOaFSrekr84hFXcka0MkFsnNMZU_omaqQXJ2pOZiNsr=w896-h267-no
so it's essentially just wasting a ton of CPU cycles to send code over the pipe.
also, fun fact
from the image, you can use cp.__class__
or type(cp)
to gain access to the deleted class MainProcess(BaseProcess):
class.
But to get back on topic, what you should do is define code in the subprocess that analyzes the input read from the pipe and interprets commands from it that are specific to your app with the supplied data.