从python中读取管道是不可能的

时间:2014-01-20 18:15:29

标签: python linux subprocess pipe popen

您好我在python 2.6中有以下代码:

command = "tcpflow -c -i any port 5559"
port_sniffer = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=1, shell=True)
while True:
    line = port_sniffer.stdout.readline()
    #do some stuff with line

此代码的目的是嗅探在端口5559上通信的两个进程(A和B)之间的流量。

现在让我描述一下我遇到的不同场景:

1)上面的代码没有运行: A和B正在通信,我可以使用日志清楚地看到它,linux命令netstat -napl | grep 5559显示进程正在所需端口上进行通信。

2)上面的代码没有运行,我通过直接从shell运行tcpflow -c -i any port 5559来嗅探: 我可以清楚地看到控制台上的通信: - )。

3)上面的代码正在运行:Proccesses无法通信。 netstat -napl | grep 5559不打印任何内容,日志会发出错误!!!

4)上面的代码在调试模式下运行:我似乎无法在行line = port_sniffer.stdout.readline()

之后继续前进

我尝试使用迭代器而不是while循环(不是它应该重要,但我仍然指出它)。我还尝试了bufsize(none,1和8)的不同值。

请帮助!!

2 个答案:

答案 0 :(得分:1)

所以在快速阅读the docs后,我发现了这两句话:

  

在Unix上,如果args是一个字符串,则该字符串被解释为名称或   要执行的程序的路径

  

shell参数(默认为False)指定是否使用   shell作为要执行的程序。如果shell为True,则为   建议将args作为字符串而不是序列传递。

基于此,我建议将命令重新创建为列表:

command = ["tcpflow -c", "-i any port 5559"]   #I don't know linux, so double check this line!!

一般的想法是这个(也来自文档):

  

如果args是序列,则第一项指定命令字符串,   任何其他项目将被视为附加参数   壳本身。也就是说,Popen相当于:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

另外,似乎要从您的流程中读取,您应该使用communicate()。所以

while True:
    line = port_sniffer.stdout.readline()

会变成

while True:
    line = port_sniffer.communicate()[0]

但请记住文档中的这条说明:

  

注意读取的数据缓冲在内存中,因此如果数据量很大或无限制,请不要使用此方法。

答案 1 :(得分:0)

如果我不得不猜测,我认为您遇到的问题是您没有以root用户身份运行程序。如果您希望能够嗅探其他人的流量(否则这将是一个严重的安全漏洞),TCPFlow需要作为privelaged用户运行。我编写了以下程序,它们适用于您的场景

server.py

#!/usr/bin/python
import socket
s = socket.socket()
host =  socket.gethostname()
port = 12345
s.bind((host,port))
s.listen(5)
while True:
    c, addr = s.accept()
    print 'Connection from', addr
    c.send('Test string 1234')
    c.recv(1024)
    while x != 'q':
        print "Received " + x
        c.send('Blah')
        x = c.recv(1024)
    print "Closing connection"
    c.close()

client.py

#!/usr/bin/python
import socket, sys
from time import sleep
from datetime import datetime
s = socket.socket()
host = socket.gethostname()
port = 12345
s.connect((host,port))
c = sys.stdin.read(1) # Type a char to send to initate the sending loop
while True:
   s.send(str(datetime.now()))
   s.sleep(3)
   msg = s.recv(1024)

flow.py

#!/usr/bin/python
import subprocess
command = 'tcpflow -c -i any port 12345'
sniffer = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
while True:
   print sniffer.stdout.readline()