ここでの問題は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 5050
sh
おそらく引数の配列を使いたいと思う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
は、すでに必要なものはすべて揃っています (そして、最初に子を殺す理由はありません)。