티스토리 뷰
현재 IP 주소를 가져오는 방법. 기록용 글.
먼저, 터미널에
open /Library/Preferences/SystemConfiguration/NetworkInterfaces.plist
를 친다.
Wi-Fi일때 en0(이런거는 물리 네트워크 인터페이스 이름이라고 보면됨) 인터페이스 사용.
en1~en4는 Thunderbolt를 의미.
info.plist에는 없지만, 셀룰러 일때는 pdp_ip0..x을 쓰는 것 같다. (내 디바이스는 pdp_ip0만 나온다.)
만약 WiFi 주소를 가져오고 싶다!고 하면
func getWiFiAddress() -> String? {
var address: String?
// Get list of all interfaces on the local machine:
var ifaddr: UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return nil }
guard let firstAddr = ifaddr else { return nil }
// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
// Check interface name:
let name = String(cString: interface.ifa_name)
if name == "en0" {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
return address
}
이렇게 하면 된다.
let name = String(cString: interface.ifa_name)
if name == "en0" {...}
위가 핵심코드. 인터페이스 이름이 en0이면 WiFi니까 WiFi주소를 가져오는거다.
근데 만약 내가 셀룰러 환경이다?
getAddress() // nil
getAddress는 nil이 되게 된다.
왜냐면 셀룰러 환경에서는 en0인터페이스가 아닌데, 저걸로 조건문을 걸고있으니 당연히 안된다.
그럼 WiFi환경이든 셀룰러환경이든 일단 IP주소를 가지고오고 싶다.
그럼 일단
1. name == "en0"조건 삭제.
2. 내가 WiFi환경인지, 셀룰러 환경인지 판단. (optional)
셀룰러를 판단하는 인터페이스 이름도
["pdp_ip0", "pdp_ip1", "pdp_ip2", "pdp_ip3"]
이런것들이 있는 것 같은데....내 디바이스에서는 pdp_ip0밖에 나오질 않는다.
# 내가 WiFi환경/셀룰러 환경인지 판단하는 방법
struct ReachabilityStatus {
enum status {
case notReachable
case reachableViaWWAN
case reachableViaWiFi
}
var currentReachabilityStatus: status {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return .notReachable
}
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return .notReachable
}
if flags.contains(.reachable) == false {
// The target host is not reachable.
return .notReachable
}
else if flags.contains(.isWWAN) == true {
// WWAN connections are OK if the calling application is using the CFNetwork APIs.
return .reachableViaWWAN
}
else if flags.contains(.connectionRequired) == false {
// If the target host is reachable and no connection is required then we'll assume that you're on Wi-Fi...
return .reachableViaWiFi
}
else if (flags.contains(.connectionOnDemand) == true || flags.contains(.connectionOnTraffic) == true) && flags.contains(.interventionRequired) == false {
// The connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs and no [user] intervention is needed
return .reachableViaWiFi
}
else {
return .notReachable
}
}
}
# 해당 환경에 따라 주소 가져오기
enum Network: String {
case wifi = "en0"
case cellular = "pdp_ip0"
}
func getAddress(for network: Network) -> String? {
var address: String?
// Get list of all interfaces on the local machine:
var ifaddr: UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return nil }
guard let firstAddr = ifaddr else { return nil }
// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
// Check interface name:
let name = String(cString: interface.ifa_name)
if name == network.rawValue {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname) + " \(name)"
}
}
}
freeifaddrs(ifaddr)
return address
}
# 사용방법
let status = ReachabilityStatus()
switch status.currentReachabilityStatus {
case .reachableViaWiFi:
self.address1.text = status.getAddress(for: .wifi)
case .reachableViaWWAN:
self.address1.text = status.getAddress(for: .cellular)
default:
break
}
사실 위 코드는
enum Network: String {
case wifi = "en0"
case cellular = "pdp_ip0"
}
이렇게 되어있고, 넘긴 network의 rawValue로 검사하고 있기 때문에...
if name == "en0" || name == "pdp_ip0"
이거랑 똑같다.
물론 인터페이스가 en0과 pdp_ip0만 있는건 아니다.
private struct InterfaceNames {
static let wifi = ["en0"]
static let wired = ["en2", "en3", "en4"]
static let cellular = ["pdp_ip0", "pdp_ip1", "pdp_ip2", "pdp_ip3"]
static let supported = wifi + wired + cellular
}
이런것들이 있을 수 있는데 이렇게 해서,
InterfaceNames.supported.contains(name)
이런식으로도 검사할 수도 있다.
하지만 이렇게 하면 어떤 인터페이스가 먼저 나오냐에 따라 결과가 달라진다.
현재.
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
...
let name = String(cString: interface.ifa_name)
if InterfaceNames.supported.contains(name) { .. }
}
이런식으로 되어있는데 for문에서
WiFi환경 + en0이 먼저나옴 -> en4가 먼저나왔다고 해보자
en0을 가져올 수 있음에도 불구하고 en4가 address로 나오게 된다.
그게 이상한(?) IP라고는 말할수는 없지만...이게 맞나 싶다.
참고로,
모든 인터페이스에 대해 address를 출력해보면,
"125.0.0.0"이런식으로 나오는 주소가 있는 반면
"ee80::111:11a1:11aa:1111%en2" (지어낸거임)
이런식으로 나오는 ip를 볼 수 있다.
이는 IPv6이며, 뒤에 인터페이스 이름이 붙는것은 "Scoped literal IPv6 addresses"라고 한다.
관련 프로젝트를 github에 올려놨다.
참고:
'iOS' 카테고리의 다른 글
iOS ) HTML String을 WKWebView에 보여주기 / WKWebView높이를 contentSize로 (0) | 2020.09.26 |
---|---|
ARKit ) ARSession / ARConfiguration (0) | 2020.09.23 |
iOS 14+ ) Select Photos 권한 작업 (2) (3) | 2020.09.20 |
iOS 14+ ) Select Photos 권한 작업 (1) (6) | 2020.09.20 |
iOS ) PHImageManager의 requestImage가 두번 호출되는 이슈. (0) | 2020.09.20 |
- SwiftUI
- github
- WidgetKit
- 스위프트
- Combine
- WWDC
- swift delegate
- fastlane
- 제이슨 파싱
- iOS delegate
- Git
- np-complete
- swift 공부
- 피아노
- swift sort
- Xcode
- 회고
- Swift
- UIBezierPath
- swift3
- Accessibility
- ios 13
- swift tutorial
- actor
- swift array
- FLUTTER
- 스위프트 문법
- IOS
- np-hard
- WKWebView
- Total
- Today
- Yesterday