我正在尝试连接到我的机器上的localhost(OS-X 10.11.2)
这是代码:
static func initClient(address address: String, port: String) -> InitClientResult {
// General purpose status variable, used to detect error returns from socket functions
var status: Int32 = 0
// ================================================================
// Retrieve the information we need to create the socket descriptor
// ================================================================
// Protocol configuration, used to retrieve the data needed to create the socket descriptor
var hints = addrinfo(
ai_flags: AI_PASSIVE, // Assign the address of the local host to the socket structures
ai_family: AF_UNSPEC, // Either IPv4 or IPv6
ai_socktype: SOCK_STREAM, // TCP
ai_protocol: 0,
ai_addrlen: 0,
ai_canonname: nil,
ai_addr: nil,
ai_next: nil)
// For the information needed to create a socket (result from the getaddrinfo)
var servinfo = UnsafeMutablePointer<addrinfo>()
// Get the info we need to create our socket descriptor
status = getaddrinfo(
address, // The IP or URL of the server to connect to
port, // The port to which will be transferred
&hints, // Protocol configuration as per above
&servinfo) // The created information
SocketUtils.logAddrInfoIPAddresses(servinfo, atLogLevel: .DEBUG, source: "SocketUtils.initClient")
// Cop out if there is an error
if status != 0 {
var strError: String
if status == EAI_SYSTEM {
strError = String(UTF8String: strerror(errno)) ?? "Unknown error code"
} else {
strError = String(UTF8String: gai_strerror(status)) ?? "Unknown error code"
}
return .ERROR(strError)
}
// ============================
// Create the socket descriptor
// ============================
let socketDescriptor = socket(
servinfo.memory.ai_family, // Use the servinfo created earlier, this makes it IPv4/IPv6 independant
servinfo.memory.ai_socktype, // Use the servinfo created earlier, this makes it IPv4/IPv6 independant
servinfo.memory.ai_protocol) // Use the servinfo created earlier, this makes it IPv4/IPv6 independant
// Cop out if there is an error
if socketDescriptor == -1 {
let strError = String(UTF8String: strerror(errno)) ?? "Unknown error code"
freeaddrinfo(servinfo)
return .ERROR(strError)
}
// =====================
// Connect to the server
// =====================
// Start with the first server address/port and work down the list in case of failures.
for (var info = servinfo; info != nil; info = info.memory.ai_next) {
// For logging only, remove if the SwifterLog instance "log" is not available or replace by your own logger.
let (address, service) = sockaddrDescription(info.memory.ai_addr)
let laddress = address ?? "nil"
let lservice = service ?? "nil"
log.atLevelNotice(id: socketDescriptor, source: "SocketUtils.initClient", message: "Trying to connect to \(laddress) at port \(lservice)")
// Attempt to connect
status = connect(socketDescriptor, info.memory.ai_addr, info.memory.ai_addrlen)
// Break if successful, log on failure.
// TODO: Remove if the SwifterLog instance "log" is not available or replace by your own logger.
if status == 0 {
log.atLevelNotice(id: socketDescriptor, source: "SocketUtils.initClient", message: "Connection established")
break
} else {
let strError = String(UTF8String: strerror(errno)) ?? "Unknown error code"
log.atLevelNotice(id: socketDescriptor, source: "SocketUtils.initClient", message: "Failed to connect with error: \(strError)")
}
}
// Cop out if there is still an error
if status != 0 {
let strError = String(UTF8String: strerror(errno)) ?? "Unknown error code"
freeaddrinfo(servinfo)
return .ERROR(strError)
}
// ===============================
// Don't need the servinfo anymore
// ===============================
freeaddrinfo(servinfo)
// Ready to start calling send(), return the socket
return .SOCKET(socketDescriptor)
}
如果我这样称呼:
initClient(address: "127.0.0.1", port: "80")
代码按预期工作。 但是当我把它称为:
initClient(address: "localhost", port "80")
完全无法连接。
生成的调试输出告诉我,在第一种情况下,我使用127 ... getaddrinfo只返回一个addrinfo元素:
DEBUG : 00000000, SocketUtils.initClient, No: 0, HostIp: 127.0.0.1 at port: 2043
NOTICE : 00000008, SocketUtils.initClient, Trying to connect to 127.0.0.1 at port 2043
NOTICE : 00000008, SocketUtils.initClient, Connection established
第一个DEBUG行来自“logAddrInfoIpAddresses”。 当我第二次使用“localhost”调用它时,调试输出如下:
DEBUG : 00000000, SocketUtils.initClient, No: 0, HostIp: ::1 at port: 2043
DEBUG : 00000000, SocketUtils.initClient, No: 1, HostIp: fe80::1%lo0 at port: 2043
DEBUG : 00000000, SocketUtils.initClient, No: 2, HostIp: 127.0.0.1 at port: 2043
NOTICE : 0000000a, SocketUtils.initClient, Trying to connect to ::1 at port 2043
NOTICE : 0000000a, SocketUtils.initClient, Failed to connect with error: Connection refused
NOTICE : 0000000a, SocketUtils.initClient, Trying to connect to fe80::1%lo0 at port 2043
NOTICE : 0000000a, SocketUtils.initClient, Failed to connect with error: Invalid argument
NOTICE : 0000000a, SocketUtils.initClient, Trying to connect to 127.0.0.1 at port 2043
NOTICE : 0000000a, SocketUtils.initClient, Failed to connect with error: Invalid argument
这两个问题是: 1)为什么不连接IPv6地址和2)为什么IPv4地址连接尝试第二次失败?