【问题标题】:Reading from pipe in python is imposiible从 python 中的管道读取是不可能的
【发布时间】:2014-02-10 01:13:44
【问题描述】:

您好,我在 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) 上面的代码正在运行:进程无法通信。 netstat -napl | grep 5559 不打印任何内容并且日志给出错误!!!

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

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

请帮忙!!

【问题讨论】:

  • tcpflow 不是标准程序。你能提供关于tcpflow -c -i any port 5559 做什么的背景吗?它只是将数据转储到文件中,还是将信息输出到 stdout/stderr?
  • tcpflow 捕获 tcp 数据包并将其消息正文(没有 tcp 开销)写入文件或控制台。 -c 标志使它的输出写入控制台。我宁愿使用 shell=True ,因为我不知道还有什么环境可以运行这个程序。
  • 问题实际上不在这段代码中。我写的代码有效

标签: python linux subprocess pipe popen


【解决方案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]

但请记住文档中的此注释:

注意读取的数据是缓存在内存中的,所以如果数据量很大或者没有限制,不要使用这种方式。

【讨论】:

  • 感谢您的意见,但我认为这不能解决问题。使用列表或字符串做同样的事情。至于通信,我没有尝试过,因为我知道它会阻塞。我想要做的是在运行时从 tcpflow 的标准输出中读取。我不想让它完成!
【解决方案2】:

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

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)

流.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()

【讨论】:

    猜你喜欢
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    相关资源
    最近更新 更多