[英]Swift obtaining ip address from socket returns weird value
I'm trying to obtain the remote ip address using getpeername()
under iOS/Swift (real hardware no emulation). 我正在尝试使用iOS / Swift下的
getpeername()
获取远程ip地址(真正的硬件没有仿真)。
This is what I'm doing: 这就是我正在做的事情:
var addr = sockaddr(sa_len: 0, sa_family: 0, sa_data: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
var len: socklen_t = socklen_t(sizeof(Int32))
if getpeername(socket, &addr, &len) != -1
{
var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
AF_INET ,
&addr,
&ipAddressString,
socklen_t(INET_ADDRSTRLEN))
println("socket \(socket) ip \(String.fromCString(ipAddressString))")
}
the values that I'm getting are: 我得到的价值是:
socket 7 ip Optional("16.2.209.237")
and that is certainly not the remote address. 那肯定不是远程地址。 Please can someone help me?
请有人帮帮我吗? What I'm doing wrong?
我做错了什么?
The main error is that inet_ntop()
takes the address of a struct in_addr
(or struct in_addr6
for IPv6), and not the address of a struct sockaddr
. 主要错误是
inet_ntop()
获取struct in_addr
的地址struct in_addr
(或struct in_addr6
用于IPv6),而不是struct sockaddr
的地址。
Another error is that the length argument to getpeername()
must be the length of the passed socket address structure, you are passing the length of an Int32
. 另一个错误是
getpeername()
的length参数必须是传递的套接字地址结构的长度,您传递的是Int32
的长度。
Your current code passes AF_INET
to inet_ntop()
and is therefore limited to IPv4 addresses. 您当前的代码将
AF_INET
传递给inet_ntop()
,因此仅限于IPv4地址。 If that is sufficient for you, the following should work: 如果这对您来说已经足够,以下情况应该有效:
var addr = UnsafeMutablePointer<sockaddr_in>.alloc(1)
var len = socklen_t(sizeofValue(addr.memory))
if getpeername(sockfd, UnsafeMutablePointer(addr), &len) != -1 {
var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
AF_INET ,
&addr.memory.sin_addr, // <-- main difference here
&ipAddressString,
socklen_t(INET_ADDRSTRLEN))
println("socket \(sockfd) ip \(String.fromCString(ipAddressString)!)")
}
addr.dealloc(1)
Allocating the socket address structure makes casting between the different pointer types a bit easier. 分配套接字地址结构使得在不同指针类型之间的转换更容易一些。 I have also replaced the variable name
socket
by sockfd
to avoid confusion with the socket()
function. 我还用
sockfd
替换了变量名socket
,以避免与socket()
函数混淆。
The more "modern" function to convert socket addresses to strings is getnameinfo()
. 将套接字地址转换为字符串的“现代”函数是
getnameinfo()
。 The following code demonstrates how to use it. 以下代码演示了如何使用它。 It works for both IPv4 and IPv6 addresses:
它适用于IPv4和IPv6地址:
var addr = UnsafeMutablePointer<sockaddr_storage>.alloc(1)
var len = socklen_t(sizeofValue(addr.memory))
if getpeername(sockfd, UnsafeMutablePointer(addr), &len) != -1 {
var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(UnsafeMutablePointer(addr), socklen_t(addr.memory.ss_len),
&hostBuffer, socklen_t(hostBuffer.count), nil, 0,
NI_NUMERICHOST) == 0) {
let host = String.fromCString(hostBuffer)!
println("socket \(sockfd) ip \(host)")
}
}
addr.dealloc(1)
Swift 2 update: First method: Swift 2更新:第一种方法:
var addr = sockaddr_in()
var len = socklen_t(sizeofValue(addr))
withUnsafeMutablePointer(&addr) {
if getpeername(sockfd, UnsafeMutablePointer($0), &len) != -1 {
var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
AF_INET ,
&addr.sin_addr, // <-- main difference here
&ipAddressString,
socklen_t(INET_ADDRSTRLEN))
print("socket \(sockfd) ip \(String.fromCString(ipAddressString)!)")
}
}
Second method: 第二种方法:
var addr = sockaddr_storage()
var len = socklen_t(sizeofValue(addr))
withUnsafeMutablePointer(&addr) {
if getpeername(sockfd, UnsafeMutablePointer($0), &len) != -1 {
var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(UnsafeMutablePointer($0), socklen_t(addr.ss_len),
&hostBuffer, socklen_t(hostBuffer.count), nil, 0,
NI_NUMERICHOST) == 0) {
let host = String.fromCString(hostBuffer)!
print("socket \(sockfd) ip \(host)")
}
}
}
apple sample code https://developer.apple.com/library/ios/samplecode/SimpleTunnel/Listings/tunnel_server_UDPServerConnection_swift.html apple示例代码https://developer.apple.com/library/ios/samplecode/SimpleTunnel/Listings/tunnel_server_UDPServerConnection_swift.html
func getEndpointFromSocketAddress(socketAddressPointer: UnsafePointer<sockaddr>) -> (host: String, port: Int)? {
let socketAddress = UnsafePointer<sockaddr>(socketAddressPointer).memory
switch Int32(socketAddress.sa_family) {
case AF_INET:
var socketAddressInet = UnsafePointer<sockaddr_in>(socketAddressPointer).memory
let length = Int(INET_ADDRSTRLEN) + 2
var buffer = [CChar](count: length, repeatedValue: 0)
let hostCString = inet_ntop(AF_INET, &socketAddressInet.sin_addr, &buffer, socklen_t(length))
let port = Int(UInt16(socketAddressInet.sin_port).byteSwapped)
return (String.fromCString(hostCString)!, port)
case AF_INET6:
var socketAddressInet6 = UnsafePointer<sockaddr_in6>(socketAddressPointer).memory
let length = Int(INET6_ADDRSTRLEN) + 2
var buffer = [CChar](count: length, repeatedValue: 0)
let hostCString = inet_ntop(AF_INET6, &socketAddressInet6.sin6_addr, &buffer, socklen_t(length))
let port = Int(UInt16(socketAddressInet6.sin6_port).byteSwapped)
return (String.fromCString(hostCString)!, port)
default:
return nil
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.