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