3

私はpythonサブプロセスをまったく正しく理解しているとは思いませんが、私が混乱している点を説明するための簡単な例を次に示します。

#!/usr/bin/env python
import subprocess
lookup_server = subprocess.Popen("nc -l 5050", shell=True)
lookup_client = subprocess.Popen("nc localhost 5050", shell=True, stdin=subprocess.PIPE) 
print lookup_client.poll()
lookup_client.stdin.write("magic\n")
print lookup_client.poll()                                                                        
lookup_client.send_signal(subprocess.signal.SIGINT)
print lookup_client.poll()
lookup_server.wait()
print "Lookup server terminated properly"

出力は次のように返されます

None
None
None

決して完了しません。どうしてこれなの?また、Popen の最初の引数をこれらすべての引数の配列に変更すると、どの nc 呼び出しも適切に実行されず、スクリプトはまったく待機せずに実行されます。なぜそれが起こるのですか?

最終的に、2 つのバージョンの nc ではなく、netcat とローカルで実行されている別のプログラムを使用して同様のことを行う、はるかに大きなプログラムで問題が発生しています。いずれにせよ、私はそれらに適切に書き込んだり読み込んだりすることができませんでした。ただし、Python コンソールでそれらを実行すると、すべてが期待どおりに実行されます。これらすべてに私は非常に不満を感じています。洞察があれば教えてください!

編集:これをUbuntu Linux 12.04で実行しています.BSD man ncGeneral Commandsマニュアルを入手したとき、これはBSD netcatであると想定しています。

4

2 に答える 2

3

ここでの問題はSIGINT、プロセスに送信していることです。closeだけの場合はstdinncソケットを閉じて終了します。これが必要です。

nc実際のプログラムでは、クライアント (サーバーではなく) に実際に使用しているように思えます。つまり、2 つの簡単な修正方法があります。

の代わりにlookup_client.send_signal(subprocess.signal.SIGINT)、ただ実行してくださいlookup_client.stdin.close()ncはこれを入力の EOF として認識し、正常に終了します。この時点で、サーバーも終了します。

#!/usr/bin/env python
import subprocess
lookup_server = subprocess.Popen("nc -l 5050", shell=True)
lookup_client = subprocess.Popen("nc localhost 5050", shell=True, stdin=subprocess.PIPE) 
print lookup_client.poll()
lookup_client.stdin.write("magic\n")
lookup_client.stdin.close()
print lookup_client.poll()
lookup_server.wait()
print "Lookup server terminated properly"

これを実行すると、最も一般的な出力は次のようになります。

None
None
magic
Lookup server terminated properly

2 番目None0代わりに、および/またはmagic前ではなく後に来ることがありますが、それ以外の場合は、常に 4 行すべてです。(私はOS Xで実行しています。)

この単純なケースでは (実際のケースではないかもしれませんが)、communicate手動で行う代わりに使用してください。

#!/usr/bin/env python
import subprocess
lookup_server = subprocess.Popen("nc -l 5050", shell=True)
lookup_client = subprocess.Popen("nc localhost 5050", shell=True, stdin=subprocess.PIPE) 
print lookup_client.communicate("magic\n")
lookup_server.wait()
print "Lookup server terminated properly"

その間:

また、Popen の最初の引数をこれらすべての引数の配列に変更すると、どの nc 呼び出しも適切に実行されず、スクリプトは待機することなく実行されます。なぜそれが起こるのですか?

ドキュメントが言うように:

Unix ではshell=True… args がシーケンスの場合、最初の項目はコマンド文字列を指定し、追加の項目はシェル自体への追加の引数として扱われます。

そのため、これらの引数をどうするかはわかりませんsubprocess.Popen(["nc", "-l", "5050"], shell=True)/bin/sh -c 'nc' -l 5050sh

おそらく引数の配列を使いたいと思うshell=Trueでしょうが、シェルはここでは役に立たないので、 —を取り除く必要があります。

もう一つ:

lookup_client.send_signal(subprocess.signal.SIGINT)
print lookup_client.poll()

SIGINTこれは、クライアントが への応答を終了し、それより前に強制終了されたかどうかに応じて、-2 または None を出力する場合がありますpoll。実際に -2 を取得したい場合は、waitではなく呼び出す必要があります (または、 None 以外を返すpollまでループするなど、何か他のことを行う必要があります)。poll

最後に、元のコードが機能しなかったのはなぜですか? 送信SIGINTは非同期です。いつ発効するかについての保証はありません。問題が発生する可能性のある例として、クライアントがソケットを開く前に有効になる可能性があります。この場合、サーバーはまだクライアントが現れるのを待っています。

time.sleep(5)これをテストするために呼び出しの前に a を投入できますがsignal、明らかにそれは本当の修正ではなく、受け入れられるハックですらありません。問題をテストする場合にのみ役立ちます。あなたがする必要があるのは、クライアントがやりたいことをすべて完了するまで、クライアントを強制終了しないことです。複雑なケースでは、それを行うための何らかのメカニズムを構築する必要があります (たとえば、stdout の読み取り)。一方、単純なケースでcommunicateは、すでに必要なものはすべて揃っています (そして、最初に子を殺す理由はありません)。

于 2012-11-20T21:08:13.173 に答える
2

あなたの呼び出しncは悪いです。コマンドラインであなたとしてこれを呼び出すとどうなりますか:

# Server window:
[vyktor@grepfruit ~]$ nc -l 5050

# Client Window
[vyktor@grepfruit ~]$ nc localhost 5050
[vyktor@grepfruit ~]$ echo $?
1

1これは (中$?) 失敗を意味します。

使用したら-p

-p, --local-port=NUM       local port number

NC はリッスンを開始するため、次のようになります。

# Server window
[vyktor@grepfruit ~]$ nc -l -p 5050
    # Keeps handing

# Client window
[vyktor@grepfruit ~]$ echo Hi | nc localhost 5050
    # Keeps hanging

-cクライアント呼び出しに追加したら:

-c, --close                close connection on EOF from stdin

あなたはこれで終わるでしょう:

# Client window
[vyktor@grepfruit ~]$ echo Hi | nc localhost 5050 -c
[vyktor@grepfruit ~]$

# Server window
[vyktor@grepfruit ~]$ nc -l -p 5050
Hi
[vyktor@grepfruit ~]$ 

したがって、次の python コードが必要です。

#!/usr/bin/env python
import subprocess
lookup_server = subprocess.Popen("nc -l -p 5050", shell=True)
lookup_client = subprocess.Popen("nc -c localhost 5050", shell=True, 
                      stdin=subprocess.PIPE) 
lookup_client.stdin.write("magic\n")
lookup_client.stdin.close()            # This
lookup_client.send_signal(subprocess.signal.SIGINT) # or this kill
lookup_server.wait()
print "Lookup server terminated properly"
于 2012-11-20T21:02:34.060 に答える