2012-02-20 121 views
3

後,我有偵聽新的連接C++ Linux的接受()阻塞插座關閉

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

線程和關閉Listen_fd當它的時間來關閉程序時,另一個線程。然而,Listen_fd關閉後,它仍然阻塞。當我使用GDB嘗試和調試accept()不會阻塞。我認爲這可能是SO_LINGER的一個問題,但它不應該默認開啓,在使用GDB時不應該改變。任何想法是怎麼回事,或任何其他建議關閉列表套接字?

回答

1

這是一種解決方法,但您可以在Listen_fd上使用select進行超時,如果發生超時,請檢查您是否要關閉該程序。如果是這樣,退出循環,如果沒有,則返回步驟1並執行下一個select

6

當對某個不是有效的套接字FD進行調用時,accept的行爲未定義。 「不是有效的套接字FD」包括曾經有效的套接字但自從被關閉的數字。您可能會說「但Borealid,它應該返回EINVAL!」,但這並不能保證 - 例如,同一個FD號碼可能被重新分配到您的closeaccept呼叫之間的不同套接字。

因此,即使您要隔離並糾正導致程序失敗的任何事情,您仍然可能在將來再次失敗。不要這樣做 - 糾正導致您嘗試在封閉套接字上連接的錯誤。

如果您意味着這是一個電話以前作出acceptclose後繼續阻塞,那麼你應該做的是發出一個信號,這是擋在accept線程。這會給它EINTR,它可以乾淨地脫開 - 然後然後關閉插座。不要使用它以外的線程關閉它。

+0

+1我的猜測是最後一個場景。線程1在接受時被阻塞。線程2關閉套接字。線程永遠阻塞。 – Duck 2012-02-20 17:21:05

+0

這是正確的。請注意,您可能需要爲您使用的信號安裝一個空信號處理程序。 – caf 2012-02-21 02:24:37

+0

哦,這部分POSIX真的很糟糕。 – thodg 2017-06-23 14:48:10

0

您是否正在檢查close的返回值? 從linux手冊頁,(http://www.kernel.org/doc/man-pages/online/pages/man2/close.2.html) 「在文件描述符可能正在使用時關閉它可能是不明智的通過在同一進程中的其他線程中進行系統調用,由於文件描述符可能會被重用,因此存在一些可能導致意想不到的副作用的模糊競爭條件。 您可以使用select而不是accept來等待來自其他thead的某個事件,然後關閉偵聽器線程中的套接字。

3

用途:sock.shutdown (socket.SHUT_RD)

然後accept將返回EINVAL。不需要醜陋的十字線信號!

從Python文檔: 「注意close()釋放資源與連接相關聯,但不一定立即關閉連接。如果你想關閉及時連接,調用shutdown()close()之前。」

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

我多年前就遇到了這個問題,而編程C.但是我只找到了解決的今天,運行到同樣的問題在Python和使用琢磨後信號(呸!),然後記住關於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 2014-11-14 01:17:58

+1

我有一個C++程序,在主線程中打開一個偵聽套接字,併產生一個子線程來接受傳入連接。主線程收到信號後需要關閉接受器線程。 'close(s)'不起作用,因爲accept(...)繼續阻塞在關閉的套接字上,但是shutdown(s,SHUT_RD)使用'EINVAL'立即接受(...)'保留。完美的解決方案,即使在發生關機時,acceptor線程處於對'accept(...)'的調用之間,它也能正常工作。謝謝! – 2016-04-02 03:56:39