ここでの問題はSIGINT、プロセスに送信していることです。closeだけの場合はstdin、ncソケットを閉じて終了します。これが必要です。
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 番目Noneが0代わりに、および/または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は、すでに必要なものはすべて揃っています (そして、最初に子を殺す理由はありません)。