恢复的GCD套接字源不会被激活

时间:2014-10-15 01:01:55

标签: macos sockets swift grand-central-dispatch

我似乎无法接受TCP连接Grand Central Dispatch来源(dispatch_source_t),我无法理解我可能做错了什么。我经历了很多材料,但我仍然无法接近(Apple's own documentationMike Ash's blog等。)

当然,我可以简单地使用第三方库(GitHub上有很多)但我正试图从中学习。谢谢。


我知道服务器在端口上正在侦听,因为使用telnet 127.0.0.1 6666 超时(但从未实际连接),而任何其他端口立即失败。我希望accept()连接的代码段永远不会运行。

class MyServer {
func startServing(#port: UInt16 = 6666) {

    // Create a listeningSocket on TCP/IPv4.
    println("\nStarting TCP server.\nCreating a listening Socket.")
    let listeningSocket = socket(AF_INET, SOCK_STREAM, 0 /*IPPROTO_TCP*/)
    if listeningSocket == -1 {
        println("Failed!")
        return
    }

    // Prepare an socket address.
    var no_sig_pipe: Int32 = 1
    setsockopt(listeningSocket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32)))

    // Working around Swift's strict initialization policies
    var addr = sockaddr_in( sin_len: __uint8_t(sizeof(sockaddr_in))
                          , sin_family: sa_family_t(AF_INET)
                          , sin_port: CFSwapInt16HostToBig(port)
                          , sin_addr: in_addr(s_addr: inet_addr("0.0.0.0"))
                          , sin_zero: (0, 0, 0, 0, 0, 0, 0, 0) )
    var sock_addr = sockaddr( sa_len: 0
                            , sa_family: 0
                            , sa_data: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) )
    memcpy(&sock_addr, &addr, UInt(sizeof(sockaddr_in)))

    // bind() the socket to the address.
    println("Binding socket to \(port).")
    if bind(listeningSocket, &sock_addr, socklen_t(sizeof(sockaddr_in))) == POSIXSocketError {
        println("Failed!")
        close(listeningSocket)
        return
    }

    // If we still have a working socket at this point...
    if listeningSocket >= 0 {
        println("Creating GCD Source.")
        connectionSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, UInt(listeningSocket), 0, dispatch_get_global_queue(0,0) /*serverQueue*/)

        if connectionSource == .None {
            println("Failed!")
            close(listeningSocket)
            return
        }

        let myself = self
        dispatch_source_set_event_handler( connectionSource, {
            // ***  This NEVER gets called!! ***
            dispatch_async(dispatch_get_main_queue(), { println("GCD Src fired.") })
            println("GCD Source triggered.")
            myself.acceptConnections(listeningSocket)
        })
        dispatch_resume(connectionSource)
    }
} // end func
} // end class

1 个答案:

答案 0 :(得分:0)

在您致电listen后,您似乎忘记了bind。来自Mike Ash's blog

  

在套接字绑定的情况下,下一步是告诉系统监听   在上面。你猜对了,这是听功能。它   有两个参数:要操作的套接字和所需的长度   用于收听的队列此队列长度告诉系统   在尝试时,您希望它连接多少个传入连接   将这些连接交给您的程序。除非你有好处   使用其他东西的理由,通过SOMAXCONN给你一个安全的,   价值很高。

因此,在您bind调用和错误检查之后,在创建调度源之前,请添加以下内容:

if listen(listeningSocket, SOMAXCONN) != 0 {
    println("Listen Failed!")
    close(listeningSocket)
    return
}

我将快速测试与您的代码以及上述更改拼凑在一起,当发生与套接字的连接时,这会触发大量GCD Src fired.GCD Source triggered.消息。