【问题标题】:GCDAsyncSocket unable to acceptOnPort more than once even after disconnecting it即使断开连接,GCDAsyncSocket 也无法多次接受 OnPort
【发布时间】:2013-04-09 16:13:06
【问题描述】:

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

【问题讨论】:

    标签: cocoa-touch sockets gcdasyncsocket


    【解决方案1】:

    参见我刚刚添加的issue 146

    GCDAsyncSocket 永远不会解除分配,因为 dispatch_source_set_event_handler 持有一个对持有 GCDAsyncSocket 自身的引用的块的引用。

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

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

    __weak GCDAsyncSocket* weakSelf = self;

    然后用weakSelf代替self调用doAccept。

    while ([weakSelf doAccept:socketFD] && (++i

    您需要重复此操作两次,一次用于 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。

    【讨论】:

    • 我进行了您建议的 __weak 更改,但在第二次尝试接受 OnPort 时仍然出现错误。我错过了什么吗?
    • 彼得,一旦我在后续的 acceptOnPort 上引入了一点延迟,你的建议就奏效了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多