即使断开连接,GCDAsyncSocket也不能多次接受OnPort

时间:2013-03-18 22:37:57

标签: cocoa-touch sockets gcdasyncsocket

我希望能够关闭当前侦听端口的套接字,然后返回它并在端口上重新建立侦听。我无法做到这一点,因为在另一台服务器上监听套接字的第二次acceptOnPort调用总是会出现错误(地址已在使用中)。如何关闭侦听套接字并重新建立新套接字?

1 个答案:

答案 0 :(得分:2)

请参阅我刚刚添加的issue 146

GCDAsyncSocket永远不会解除分配,因为dispatch_source_set_event_handler持有对一个块的引用,该块保存对GCDAsyncSocket self的引用。

这导致无法关闭然后重新打开GCDAsyncSocket侦听器,因为该地址已在使用中。

这可以通过将引用更改为弱引用来解决。在dispatch_source_set_event_handler之前,添加以下行:

__弱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。