[英]Get line-based output from pipe in real-time
我想實時(接近)實時讀取tcpdump子進程的行輸出,但是我需要選擇評估管道是否為空(因此隊列)的選項。 線程等待0.5秒,獲取所有排隊的輸出行,對其進行處理(例如,平均分配0.5秒內的數據包)並返回內容。
最小的無效示例:
millis = lambda: int(round(time.time() * 1000))
def enqueue_output(out, queue):
for line in iter(out.readline, b''):
print(millis())
print(line)
queue.put(line)
out.close()
def infiniteloop1():
p = Popen( [ 'sudo', 'tcpdump', '-i', 'wlan0', '-nn', '-s0', '-q', '-l', '-p', '-S' ], stdout=subprocess.PIPE, stderr=STDOUT)
q = Queue()
t = Thread(target=enqueue_output, args=(p.stdout, q))
t.daemon = True # thread dies with the program
t.start()
while True:
while True:
# read line without blocking
try:
row = q.get_nowait() # or q.get(timeout=.1)
except Empty:
print('empty')
break
else:
pass
time.sleep(0.5)
thread1 = threading.Thread(target=infiniteloop1)
thread1.daemon = True
thread1.start()
捕獲連續包流時的輸出:
[...]
1552905183422
10:33:03.334167 IP 192.168.1.2.36189 > a.b.c.d.443: tcp 437
1552905183422
10:33:03.357215 IP a.b.c.d.443 > 192.168.1.2.36189: tcp 0
1552905183423
10:33:03.385145 IP 192.168.1.2.36189 > a.b.c.d.443: tcp 437
empty
empty
1552905184438
10:33:03.408408 IP a.b.c.d.443 > 192.168.1.2.36189: tcp 0
1552905184439
10:33:03.428045 IP 192.168.1.2.36189 > a.b.c.d.443: tcp 437
1552905184439
10:33:03.451235 IP a.b.c.d.443 > 192.168.1.2.36189: tcp 0
[...]
注意兩個連續的“空”。 tcpdump在10:33:03.385145捕獲了第一個“空”之前的最后一個數據包,並在1552905183423處將其傳遞到隊列,這花費了38 ms。 在兩個“空”之間,沒有數據包被傳遞到隊列中。 在第二個“空”之后的第一個包在10:33:03.408408處捕獲並交付1552905184438,在前一個數據包之后1秒交付,但在“空”之間捕獲。 為什么沒有在“空”之間傳遞? 這種情況很少發生,但是每隔一秒鍾彈出隊列就會導致沒有包裹交付,這是為什么呢?
在第二個“空”之后的第一個包在10:33:03.408408處捕獲並交付1552905184438,在前一個數據包之后1秒交付,但在“空”之間捕獲。
給定您的代碼,僅當for line in iter(out.readline, b'')
返回一個新項時,才計算和打印系統時間戳,因此延遲似乎來自此。
我懷疑stdio緩沖是罪魁禍首。 在Linux(即libc / glibc)上,如果STDOUT描述符引用了TTY,則啟用行緩沖。 如果它引用了其他內容(例如管道),則STDOUT描述符已完全緩沖; 在調用寫入系統調用之前,您的進程需要填充4096字節(Linux上為默認值)。
根據此處顯示的輸出進行非常粗略的計算,您的子進程似乎每〜0.025秒生成〜65個字節。 給定4kB緩沖區,將需要約1.625秒的時間將其填滿並觸發刷新/寫入。
從該subprocess.PIPE
進程中讀取subprocess.PIPE
並將輸出發送到主進程的stdout所花費的時間要少得多,因此,您將看到帶有tcpdump
輸出的突發,即在幾微秒內打印(從stdout迭代器接收到)間隔約25ms,並且您的程序隨后等待,直到刷新下一個4kB。
如果可以安裝第3方軟件包(並使用Python> = 2.7),則可能需要看看pexpect 。 該程序包的子程序連接到PTY,使系統將它們視為交互式程序,因此其stdout描述符是行緩沖的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.