2012-02-20 1 views
3

を閉じた後、私は新しい接続はソケットが

new_fd = accept(Listen_fd, (struct sockaddr *) & their_addr, &sin_size); 

と、それはプログラムを終了する時が来たときにListen_fdを閉じて、別のスレッドをリッスンするスレッドを持ってブロックする)(受け入れます。 Listen_fdを閉じた後も、それはまだブロックされます。私がGDBを使ってaccept()をデバッグしようとするとブロックされません。私はそれがSO_LINGERの問題かもしれないと思ったが、デフォルトではオンにすべきではなく、GDBを使うときに変更すべきではない。何が起こっているか、またはリスティングソケットを閉じるための他の提案?

答えて

1

これは回避策ですが、のListen_fdにタイムアウトを設定して、タイムアウトが発生してプログラムを終了しようとしていることを確認できます。そうであれば、ループを終了し、そうでなければ、ステップ1に戻り、次のステップを実行する。select

6

有効なソケットFDでないものに対して呼び出されたときの動作は、定義されていません。accept 「有効なソケットFDではありません」とは、かつては有効なソケットであったものの、その後閉鎖された番号を含みます。 「しかしBorealid、EINVALを返すことになっています!」と言うかもしれませんが、それは保証されていません。たとえば、同じFD番号がcloseacceptコールの間で別のソケットに割り当てられます。

したがって、プログラムを失敗させるものを切り離して修正しても、今後も失敗する可能性があります。しないでください - 閉じたソケットの接続をacceptにしようとするエラーを修正してください。

あなたは以前作らacceptにした呼び出しがcloseブロッキングを続けていることを意味している場合、何を行うべきことacceptにブロックされたスレッドにシグナルを送っています。これはEINTRを与え、きれいに外れることができます - そしてそしてはソケットを閉じます。それを使用しているスレッド以外のスレッドからは閉じないでください。

+0

+1私の推測では、最後のシナリオです。スレッド1はacceptでブロックしています。スレッド2はソケットを閉じます。スレッド1は永遠にブロックします。 – Duck

+0

これは正しいです。使用している信号用の空のシグナルハンドラをインストールしたいと思うことに注意してください。 – caf

+0

ああ、POSIXのこの部分は本当に吸う。 – thodg

0

閉じるの戻り値を確認していますか? linuxのマンページから、(http://www.kernel.org/doc/man-pages/online/pages/man2/close.2.html) "使用中のファイル記述子を閉じることはおそらく賢明ではありませんファイルディスクリプタが再利用される可能性があるため、意図しない副作用の原因となるかもしれない不明瞭な競合条件があります。 acceptの代わりにselectを使用し、もう一方のイベントからいくつかのイベントを待ってから、リスナー・スレッドのソケットを閉じることができます。

3

用途:sock.shutdown (socket.SHUT_RD)

その後acceptEINVALを返します。醜いクロススレッド信号は必要ありません! Pythonドキュメントから

:「。あなたがタイムリーに接続を閉じたい場合は、close()shutdown()を呼び出すclose()リリース接続に関連付けられたリソースを注意したが、必ずしもすぐに接続を閉じていない」 C.しかし、私でのプログラミングのみ使用して信号をPythonで同じ問題に実行している、と熟考した後、今日の解決策を発見しながら、

http://docs.python.org/3/library/socket.html#socket.socket.close

は、私が(不潔!)、その後、数年前にこの問題に遭遇しましたメモをshutdownについて覚えておいてください!

スレッド間でソケットを閉じる/使用しないでください... CPythonでは、グローバルなインタプリタロックがあなたを保護するはずです(生の整数ファイル記述子ではなくファイルオブジェクトを使用していると仮定します)。ここで

は例のコードは次のとおりです。

import socket, threading, time 

sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM) 
sock.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sock.bind (('', 8000)) 
sock.listen (5) 

def child(): 
    print ('child accept ...') 
    try: sock.accept() 
    except OSError as exc : print ('child exception %s' % exc) 
    print ('child exit') 

threading.Thread (target = child).start() 

time.sleep (1) 
print ('main shutdown') 
sock.shutdown (socket.SHUT_RD) 

time.sleep (1) 
print ('main close') 
sock.close() 

time.sleep (1) 
print ('main exit') 
+2

これは素晴らしいです、ありがとう! – Guido

+1

メインスレッドでリスンソケットを開き、着信接続を受け入れる子スレッドを生成するC++プログラムがあります。メインスレッドは、シグナルを受信するとアクセプタスレッドをシャットダウンする必要があります。 'accept(...)'が閉じられたソケット上でブロックし続けているので 'close(s)'は動作しませんが 'shutdown(s、SHUT_RD)'は 'accept(...)'呼び出しを 'EINVAL'完璧なソリューションであり、アクセプタスレッドがシャットダウン時にaccept(...)を呼び出す間であっても機能します。ありがとう! –

関連する問題