2017-08-10 108 views
0

我想在Swift中實現一個簡單的TCP套接字服務器。這段代碼應該與C實現非常相似,但帶有額外的Swift-isms。DispatchReadSource事件處理程序不會觸發綁定套接字

我試圖連接使用curl http://localhost:8080哪些應該至少觸發「接受」,即使服務器中沒有HTTP邏輯。 curl的響應是Connection refused

這是我正在使用的代碼。它輸出2 「上偵聽描述符」 行,但沒有 「接受......」 行

import LibC 
import Dispatch 

let port = 8080 
let listenBacklogLen = 16 

// Setup Sockets 
let socketDescriptor = (
    ipv4: socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), 
    ipv6: socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP) 
) 
let descriptors = [socketDescriptor.ipv4, socketDescriptor.ipv6] 

var address = (
    ipv4: sockaddr_in(), 
    ipv6: sockaddr_in6() 
) 

address.ipv4.sin_len = UInt8(MemoryLayout<sockaddr_in>.size) 
address.ipv4.sin_family = sa_family_t(AF_INET) 
address.ipv4.sin_port = in_port_t(port) 
address.ipv4.sin_addr.s_addr = INADDR_ANY 

address.ipv6.sin6_len = UInt8(MemoryLayout<sockaddr_in>.size) 
address.ipv6.sin6_family = sa_family_t(AF_INET6) 
address.ipv6.sin6_port = in_port_t(port) 
address.ipv6.sin6_addr = in6addr_any 

var reuseAddress: Int = 1 
let reuseAddressLen = socklen_t(MemoryLayout.size(ofValue: reuseAddress)) 
withUnsafePointer(to: &reuseAddress) { ref in 
    for descriptor in descriptors { 
     assert(setsockopt(descriptor, SOL_SOCKET, SO_REUSEADDR, ref, reuseAddressLen) == 0) 
    } 
} 

withUnsafePointer(to: &address.ipv4) { ref in 
    ref.withMemoryRebound(to: sockaddr.self, capacity: 1) { reboundRef in 
     assert(bind(socketDescriptor.ipv4, reboundRef, socklen_t(MemoryLayout.size(ofValue: ref.pointee))) == 0) 
    } 
} 
withUnsafePointer(to: &address.ipv6) { ref in 
    ref.withMemoryRebound(to: sockaddr.self, capacity: 1) { reboundRef in 
     assert(bind(socketDescriptor.ipv6, reboundRef, socklen_t(MemoryLayout.size(ofValue: ref.pointee))) == 0) 
    } 
} 

var acceptSources: [DispatchSourceRead] = [] 
var requestSources: [DispatchSourceRead] = [] 
for descriptor in descriptors { 
    assert(listen(descriptor, Int32(listenBacklogLen)) == 0); 

    let source = DispatchSource.makeReadSource(fileDescriptor: descriptor, queue: .global(qos: .userInitiated)) 
    source.setEventHandler { 
     print("Accepting…") 
     var address = sockaddr() 
     var addressLen: socklen_t = socklen_t(MemoryLayout.size(ofValue: address)) 
     let requestSocketDescriptor = accept(descriptor, &address, &addressLen) 
     assert(requestSocketDescriptor >= 0) 

     let source = DispatchSource.makeReadSource(fileDescriptor: requestSocketDescriptor, queue: .global(qos: .userInitiated)) 
     source.setEventHandler { [unowned source] in 
      var char: CChar = 0 
      let bytesRead = read(requestSocketDescriptor, &char, 1) 
      switch bytesRead { 
      case -1: 
       if ![EAGAIN, EINTR].contains(errno) { 
        print("Read returned error (\(errno)): \(strerror(errno))") 
        fallthrough 
       } 
      case 0: 
       print("Done") 
       source.cancel() 
      default: 
       print("C: \(char)") 
      } 
     } 
     requestSources.append(source) 
     source.resume() 
    } 
    acceptSources.append(source) 

    print("Listening on descriptor: \(descriptor)") 
    source.resume() 
} 

dispatchMain() 

BTW,LibC是一個簡單的模塊,統一的glibc和達爾文:

#if os(Linux) 
    @_exported import Glibc 
#else 
    @_exported import Darwin.C 
#endif 

回答

相關問題