如何从subprocess.Popen调用stdout.write?

时间:2014-02-26 13:44:17

标签: python udp popen

我正在尝试通过stdout将使用subprocess.Popen()执行的命令记录到UDP套接字。我已经看过网上的尝试,但至少在我的情况下没有真正的成功。

有些人试图将套接字子类化并将其传递给Popen的“stdout”参数,以覆盖默认的.write方法以通过套接字发送,例如, http://www.dreamincode.net/forums/topic/209734-using-a-socket-as-stdinstdout/

我还尝试子类化“file”类并使用我的实现覆盖write方法,但Popen似乎根本没有调用任何write方法。

实际上,这种子类化的想法并不适用于Popen(args,stdout = mysocket)不调用任何mysocket.write(或任何.write)方法的简单原因。为了测试这个,我在调试模式下调用了Popen并尝试从 init 跳到最后但没有找到任何.write或类似的东西。我正在使用python 2.7

当然我知道我可以将stdout发送到PIPE然后读取它,但是在我的情况下需要创建(不止一个)工作线程来读取PIPE并发送,如果可能的话我想避免这个解决方案如果更简单的一个可以用更少的努力。

我的文件子类

class Foo(file):
    dbgIP = ""
    dbgPORT = 0
    sck = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

    def __init__(self, dbgIP, dbgPORT):
        file.__init__(self,"empty",'w')
        self.sck.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
        self.dbgIP = dbgIP
        self.dbgPORT = dbgPORT

    def write(self, text):
        return self.sck.sendto(text, (self.dbgIP, self.dbgPORT))

示例电话

foofile = Foo(MCAST_GROUP,MCAST_PORT)
subprocess.Popen("jackd -R -P62 -dalsa -dhw:0 -p256 -n2 -i2 -o2 -s -S -r22050",shell=True, stdout=foofile, stderr=subprocess.STDOUT)

调用foofile.write("asd")可以正常工作

1 个答案:

答案 0 :(得分:0)

Popen()适用于文件描述符(处理程序)级别。这意味着子类化和覆盖.write()方法将不起作用。在某些系统上real socket (valid .fileno()) can be passed to stdout as is

from subprocess import call, STDOUT

rc = call("./generate-output", stdout=sck, stderr=STDOUT)

在其他系统上,您可以手动完成:

import shutil
from subprocess import Popen, PIPE, STDOUT

p = Popen("./generate-output", stdout=PIPE, stderr=STDOUT, bufsize=-1)
shutil.copyfileobj(p.stdout, foofile)
p.stdout.close()
rc = p.wait()

在更一般的情况下,您可以使用与teed_call()类似的内容。


  

1)将套接字用作stdout,如何确定哪些系统可以工作?这取决于Unix flavor / Win,还是python版本?

我在Linux上尝试过。我希望它能在POSIX系统上运行。

  

2)如果我想继承套接字,我应该修改哪些方法,例如将字符串添加到来自stdout的字符串?

在这种情况下,您不应该继承socket。 .fileno()是唯一由subprocess调用的方法。 “在文件描述符级别工作”意味着一旦你给出文件描述符并且重定向发生,其余的就是内核业务。

  

3)我假设带有copyfileobj的代码将启动从stdout复制到foofile,直到进程处于活动状态。但是关闭stdout会不会阻止进程和foofile之间的通信? -

copyfileobj()复制到p.stdout中的EOF。 It is pure Python

def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    while 1:
        buf = fsrc.read(length)
        if not buf:
            break
        fdst.write(buf)
调用

p.stdout.close()以避免泄漏文件描述符(清理)。

有一个缓冲区,因此在子进程终止后仍可能发生复制。并且因为子进程可能在它仍然存活时关闭它的stdout。