2017-05-07 13 views
0

Socket.close()は、そのソケットですでに実行されているsocket.accept()呼び出しをブロックしません。閉じたunixソケットでsocket.accept()を呼び出す

Pythonプログラムには、すでに閉じられているunixドメインソケットでblocking socket.accept()を呼び出すスレッドがいくつかあります。 socket.accept()呼び出しを停止するか、 例外を発生させることによって、これらのスレッドを強制終了します。

私は、プログラムを停止することなく、プログラムに新しいコードをロードすることでこれを実行しようとしています。 したがって、これらのスレッドを生成したコードまたはソケットを閉じたコードを変更することは選択できません。

これを行う方法はありますか?

これはhttps://stackoverflow.com/a/10090348/3084431に似ていますが、これらのソリューションは、私のコードのための作業を習慣:

  1. この点は真実ではない、閉鎖は受け入れに例外を発生しません。シャットダウンしますが、スレッドが閉じられてもそれを呼び出すことはできません。
  2. 私はこのソケットにもう接続できません。ソケットが閉じています。
  3. accept呼び出しのスレッドは既に実行されており、変更できません。明確化のために3

と同じ

  • 、私はこの問題を持っているいくつかのサンプルコードを書かれています。 このコード私は必要なもののpython 2とPython 3

    import socket 
    import threading 
    import time 
    
    address = "./socket.sock" 
    
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 
    sock.bind(address) 
    sock.listen(5) 
    
    def accept(): 
        print(sock.accept()) 
    
    t = threading.Thread(target=accept, name="acceptorthread") 
    t.start() 
    
    sock.close() 
    
    time.sleep(0.5) # give the thread some time to register the closing 
    
    print(threading.enumerate()) # the acceptorthread will still be running 
    

    の両方で動作しますが、このコードは何とかアクセプタスレッドを停止することができる終えた後、私は実行することができるものです。

  • +0

    ストックソケットの動作に問題がありますか? 'accept'が「既に実行中」であれば、新しい接続を受け入れる前に接続が技術的に受け入れられました - それで大丈夫です。既存のクライアントをすべて蹴りたいなら、それはむしろやるべきことです。 –

    +1

    この作業は決してできません。あなたのコードはすでに重大な競合状態にあります。 'sock.close()'が 'accept'の呼び出しと同時に実行されるとどうなりますか? Pythonのソケットオブジェクトはスレッドセーフではありません。あるスレッドで別のスレッドがアクセスしている間は、そのスレッドの状態を変更することはできません。実行するか、ブロックする準備をするのとは対照的に、 'accept'が確実に実行できるかどうかはまったくありません。だから、これは安全に行うことはできません。 –

    +0

    @ivan_pozdeevクライアントは存在しません。永久に待機してスレッドが終了しないようにするのは、単に「accept」機能です。 @DavidSchwartz 'sock.close'は' sock.accept'の実行中に実際に実行されます。問題は、ソケットは現在閉じているが、 'sock.accept'はまだ動いているということです。 – Troido

    答えて

    1

    すべてのリスナーにソケットがクローズされたことを通知するメカニズムはありません。あなたは自分で何かを書く必要があります。簡単な解決策は、ソケットにタイムアウトを使用することです:

    sock.settimeout(1) 
    
    def accept(): 
        while True: 
         try: 
          print(sock.accept()) 
         except socket.timeout: 
          continue 
         break 
    

    あなたはソケットを閉じたときに今.accept()次の呼び出し(タイムアウトの後)は、「悪い記述」例外がスローされます。

    また、PythonのソケットAPIはスレッドセーフではありません。マルチスレッド環境では、ソケット呼び出しをロック(または他の同期メソッド)でラップすることをお勧めします。

    さらに高度な(そして効率的な)ソケットは、select callでラップしてください。ソケットを使用するには、非ブロックモードである必要はありません。

    したがって、これらのスレッドを生成したコードを変更するか、ソケットを閉じたコードを変更することは選択できません。

    この場合、あなたは破棄されます。スレッド内で動作するコードを変更することなく、達成することは不可能です。それは "私は車を変更せずに私の壊れた車を修正することができます"と尋ねるようなものです。起こらない、仲間。

    +0

    ソケットが閉じられないと修正することができました。クローズされなかった場合、 'sock.shutdown'は' accept'関数のエラーを引き起こし、スレッドを停止させます。それでも、ソケットが閉じられているときに、このようなsometingを実行することはほとんど不可能です。私はちょうど誰かがこれを行うためのトリックを知って起こることを望んでいた。 – Troido

    0

    selectorsから「読み取り可能な」結果が得られたソケットでのみ、.accept()を呼び出す必要があります。その後、受け入れられないを中断する必要があります。

    偽のウェイクアップの場合は、とにかくO_NONBLOCKモードのリスニングソケットが必要です。

    関連する問題