前端之家收集整理的这篇文章主要介绍了
在Windows上发送^ C到Python子进程对象,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个测试工具(用Python编写),需要通过发送^ C来
关闭被测程序(用C编写)。在Unix上,
proc.send_signal(signal.SIGINT)
工作完美。在Windows上,会引发错误(“不支持信号2”)。我正在使用Python 2.7 for Windows,所以我有一个印象,我应该能够做到
proc.send_signal(signal.CTRL_C_EVENT)
但这根本不做任何事情。我需要做什么?这是创建子进程的代码:
# Windows needs an extra argument passed to subprocess.Popen,# but the constant isn't defined on Unix.
try: kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP
except AttributeError: pass
proc = subprocess.Popen(argv,stdin=open(os.path.devnull,"r"),stdout=subprocess.PIPE,stderr=subprocess.PIPE,**kwargs)
@H_
403_12@
通过使用Windows启动命令在新的控制台窗口中启动的包装器(如提供的Vinay
链接中所述)有一个
解决方案。
包装的代码:
#wrapper.py
import subprocess,time,signal,sys,os
def signal_handler(signal,frame):
time.sleep(1)
print 'Ctrl+C received in wrapper.py'
signal.signal(signal.SIGINT,signal_handler)
print "wrapper.py started"
subprocess.Popen("python demo.py")
time.sleep(3) #Replace with your IPC code here,which waits on a fire CTRL-C request
os.kill(signal.CTRL_C_EVENT,0)
程序代码捕获CTRL-C:
#demo.py
import signal,time
def signal_handler(signal,frame):
print 'Ctrl+C received in demo.py'
time.sleep(1)
sys.exit(0)
signal.signal(signal.SIGINT,signal_handler)
print 'demo.py started'
#signal.pause() # does not work under Windows
while(True):
time.sleep(1)
启动包装器,如:
PythonPrompt> import subprocess
PythonPrompt> subprocess.Popen("start python wrapper.py",shell=True)
您需要添加一些IPC代码,允许您控制包装器触发os.kill(signal.CTRL_C_EVENT,0)命令。我在应用程序中为此使用了套接字。
说明:
Preinformation
> send_signal(CTRL_C_EVENT)不起作用,因为CTRL_C_EVENT仅适用于os.kill。 [REF1]
> os.kill(CTRL_C_EVENT)将信号发送到当前cmd窗口[REF2]中运行的所有进程
> Popen(…,creationflags = CREATE_NEW_PROCESS_GROUP)不起作用,因为进程组忽略了CTRL_C_EVENT。 [REF2]
这是python文档[REF3]中的一个错误
实施解决方案
>让你的程序运行在不同的cmd窗口中,Windows Shell命令启动。
>在控制应用程序和应用程序之间添加一个CTRL-C请求包装器,该应用程序应该获得CTRL-C信号。包装器将与应该获得CTRL-C信号的应用程序在同一个cmd窗口中运行。
>包装器将关闭本身以及通过发送cmd窗口中的所有进程CTRL_C_EVENT来获取CTRL-C信号的程序。
>控制程序应该能够请求包装器发送CTRL-C信号。这可能通过IPC手段实现。插座。
有用的帖子是:
我不得不删除链接前面的http,因为我是一个新用户,不允许发布两个以上的链接。
> http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/dc9586ab-1ee8-41aa-a775-cf4828ac1239/#6589714f-12a7-447e-b214-27372f31ca11
> Can I send a ctrl-C (SIGINT) to an application on Windows?
> Sending SIGINT to a subprocess of python
> http://bugs.python.org/issue9524
> http://ss64.com/nt/start.html
> http://objectmix.com/python/387639-sending-cntrl-c.html#post1443948
更新:基于IPC的CTRL-C Wrapper
在这里,您可以找到一个自写的python模块,提供包含基于插座的IPC的CTRL-C包装。
语法与子进程模块非常相似。
用法:
>>> import winctrlc
>>> p1 = winctrlc.Popen("python demo.py")
>>> p2 = winctrlc.Popen("python demo.py")
>>> p3 = winctrlc.Popen("python demo.py")
>>> p2.send_ctrl_c()
>>> p1.send_ctrl_c()
>>> p3.send_ctrl_c()
码
import socket
import subprocess
import time
import random
import signal,os,sys
class Popen:
_port = random.randint(10000,50000)
_connection = ''
def _start_ctrl_c_wrapper(self,cmd):
cmd_str = "start \"\" python winctrlc.py "+"\""+cmd+"\""+" "+str(self._port)
subprocess.Popen(cmd_str,shell=True)
def _create_connection(self):
self._connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self._connection.connect(('localhost',self._port))
def send_ctrl_c(self):
self._connection.send(Wrapper.TERMINATION_REQ)
self._connection.close()
def __init__(self,cmd):
self._start_ctrl_c_wrapper(cmd)
self._create_connection()
class Wrapper:
TERMINATION_REQ = "Terminate with CTRL-C"
def _create_connection(self,port):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('localhost',port))
s.listen(1)
conn,addr = s.accept()
return conn
def _wait_on_ctrl_c_request(self,conn):
while True:
data = conn.recv(1024)
if data == self.TERMINATION_REQ:
ctrl_c_received = True
break
else:
ctrl_c_received = False
return ctrl_c_received
def _cleanup_and_fire_ctrl_c(self,conn):
conn.close()
os.kill(signal.CTRL_C_EVENT,0)
def _signal_handler(self,frame):
time.sleep(1)
sys.exit(0)
def __init__(self,cmd,port):
signal.signal(signal.SIGINT,self._signal_handler)
subprocess.Popen(cmd)
conn = self._create_connection(port)
ctrl_c_req_received = self._wait_on_ctrl_c_request(conn)
if ctrl_c_req_received:
self._cleanup_and_fire_ctrl_c(conn)
else:
sys.exit(0)
if __name__ == "__main__":
command_string = sys.argv[1]
port_no = int(sys.argv[2])
Wrapper(command_string,port_no)