2013-03-18 35 views
1

我希望能夠關閉當前偵聽端口的套接字,然後再回到端口並重新建立偵聽端口。我無法這樣做,因爲在另一個服務器偵聽套接字上的第二個acceptOnPort調用總是以錯誤結束(地址已被使用)。我怎樣才能關閉一個監聽套接字並重新建立一個新套接字呢?GCDAsyncSocket即使斷開連接後也不能多次接受端口

回答

2

請參閱我剛剛添加的issue 146

GCDAsyncSocket不會釋放,因爲dispatch_source_set_event_handler持有對保存對GCDAsyncSocket self的引用的塊的引用。

由於地址已被使用,導致無法關閉然後重新打開GCDAsyncSocket偵聽器。

這可以通過將引用更改爲弱引用來解決。在dispatch_source_set_event_handler之前,添加以下行:

__weak GCDAsyncSocket * weakSelf = self;

然後使用weakSelf而不是self來調用doAccept。

while([weakSelf doAccept:socketFD] & &(++ i < numPendingConnections));

您需要重複兩次,一次是ipv4,一次是ipv6。

在這一點上,你會發現它是一件好事GCDAsyncSocket從來沒有被處理,因爲它會立即崩潰dealloc運行。這是因爲dealloc調用closeWithError,後者又調用委託socketDidDisconnect,將GCDAsyncSocket self作爲參數傳遞。 ARC會立即保留當GCDAsyncSocket當前正在解除分配時崩潰的GCDAsyncSocket。

這可以通過將「delegate = nil」移動到dealloc的開頭來解決,您可以這樣做,因爲在那時無法安全地調用委託(如果您想要,這是不可能的能夠通過GCDAsyncSocket,你不能再這樣做)。另一種方法是在這種情況下調用socketDidDisconnect:nil。

無論哪種方式,這意味着socketDidDisconnect不會被調用,或者不會被調用適當的GCDAsyncSocket作爲參數,這可能會破壞API合約,但在這一點上是不可避免的。

更好的API應該是在發生dealloc之前有某種「Kill」方法調用來殺死GCDAsyncSocket。

+0

我對您的建議進行了__weak更改,並且在嘗試第二次接受OnPort時仍出現錯誤。我錯過了什麼? – Boon 2014-02-27 21:40:18

+0

Peter,一旦我在隨後的acceptOnPort上引入了一點點延遲,你的建議就可以工作。謝謝! – Boon 2014-02-27 21:59:09