在Windows上发送^ C到Python子进程对象

前端之家收集整理的这篇文章主要介绍了在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)
通过使用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)

猜你在找的Windows相关文章