отслеживание/мониторинг использования данных iPhone
Я искал по этой теме, но нашла очень мало деталей, которые были полезны. С этими деталями я попытался приготовить некоторый код следующим образом.
Примечание: пожалуйста, сравните детали, разделяемые в этом посте с другими сообщениями, прежде чем отмечать это как дубликат, а не только по теме.
- (NSArray *)getDataCountersForType:(int)type {
BOOL success;
struct ifaddrs *addrs = nil;
const struct ifaddrs *cursor = nil;
const struct sockaddr_dl *dlAddr = nil;
const struct if_data *networkStatisc = nil;
int dataSent = 0;
int dataReceived = 0;
success = getifaddrs(&addrs) == 0;
if (success) {
cursor = addrs;
while (cursor != NULL) {
if (cursor->ifa_addr->sa_family == AF_LINK) {
dlAddr = (const struct sockaddr_dl *) cursor->ifa_addr;
networkStatisc = (const struct if_data *) cursor->ifa_data;
if (type == WiFi) {
dataSent += networkStatisc->ifi_opackets;
dataReceived += networkStatisc->ifi_ipackets;
}
else if (type == WWAN) {
dataSent += networkStatisc->ifi_obytes;
dataReceived += networkStatisc->ifi_ibytes;
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
return [NSArray arrayWithObjects:[NSNumber numberWithInt:dataSent], [NSNumber numberWithInt:dataReceived], nil];
}
этот код собирает информацию об использовании интернета устройства iPhone (а не только мое приложение).
теперь, если я использую интернет через WiFi или через 3G, я получаю данные (байты) только в ifi_obytes
(отправлено) и ifi_ibytes
(получено) но я думаю, что я должен получить использование WiFi в ifi_opackets
и ifi_ipackets
.
также хотел добавить, что если я подключен к сети Wi-Fi, но не использую интернет, я все равно получаю добавленную стоимость ifi_obytes
и ifi_ibytes
.
может быть я ошибаюсь в реализации или понимания. Нужен кто-то, чтобы помочь мне.
Edit: вместо AF_LINK
пробовал AF_INET
(sockaddr_in
вместо sockaddr_dl
). Это приводит к сбою приложения.
6 ответов:
дело в том, что pdp_ip0 является одним из интерфейсов, все pdpXXX-это интерфейсы WWAN, предназначенные для различных функций, голосовой почты, общего сетевого интерфейса.
Я читал в форуме Apple, что : ОС не ведет статистику сети на основе процесса за процессом. Таким образом, нет точного решения этой проблемы. Однако вы можете получить сетевую статистику для каждого сетевого интерфейса.
В общем en0-это ваш Wi-Fi интерфейс, а pdp_ip0-ваш WWAN взаимодействие.
нет хорошего способа получить информацию wifi / данные сотовой сети, так как, конкретная дата-время!
статистика данных (ifa_data - >ifi_obytes и ifa_data - >ifi_ibytes) сохраняются с предыдущей перезагрузки устройства.
Я не знаю, почему, но ifi_opackets и ifi_ipackets показаны только для lo0 (я думаю, что его основной интерфейс ).
да. Затем устройство подключается через WiFi и не использует интернет, если значения if_iobytes все еще приходят, потому что это метод обеспечивает обмен байтами в сети, а не только в интернете .
#include <net/if.h> #include <ifaddrs.h> static NSString *const DataCounterKeyWWANSent = @"WWANSent"; static NSString *const DataCounterKeyWWANReceived = @"WWANReceived"; static NSString *const DataCounterKeyWiFiSent = @"WiFiSent"; static NSString *const DataCounterKeyWiFiReceived = @"WiFiReceived"; NSDictionary *DataCounters() { struct ifaddrs *addrs; const struct ifaddrs *cursor; u_int32_t WiFiSent = 0; u_int32_t WiFiReceived = 0; u_int32_t WWANSent = 0; u_int32_t WWANReceived = 0; if (getifaddrs(&addrs) == 0) { cursor = addrs; while (cursor != NULL) { if (cursor->ifa_addr->sa_family == AF_LINK) { #ifdef DEBUG const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data; if (ifa_data != NULL) { NSLog(@"Interface name %s: sent %tu received %tu",cursor->ifa_name,ifa_data->ifi_obytes,ifa_data->ifi_ibytes); } #endif // name of interfaces: // en0 is WiFi // pdp_ip0 is WWAN NSString *name = @(cursor->ifa_name); if ([name hasPrefix:@"en"]) { const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data; if (ifa_data != NULL) { WiFiSent += ifa_data->ifi_obytes; WiFiReceived += ifa_data->ifi_ibytes; } } if ([name hasPrefix:@"pdp_ip"]) { const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data; if (ifa_data != NULL) { WWANSent += ifa_data->ifi_obytes; WWANReceived += ifa_data->ifi_ibytes; } } } cursor = cursor->ifa_next; } freeifaddrs(addrs); } return @{DataCounterKeyWiFiSent : @(WiFiSent), DataCounterKeyWiFiReceived : @(WiFiReceived), DataCounterKeyWWANSent : @(WWANSent), DataCounterKeyWWANReceived : @(WWANReceived)}; }
улучшена поддержка копирования/вставки !
важно понимать, что эти счетчики предусмотренного С момента последней загрузки устройства.
Итак, чтобы эффективно использовать их, вы должны сопровождать каждый образец с временем безотказной работы устройства (вы можете использовать mach_absolute_time () - см. этой для получения дополнительной информации)
Как только у вас есть счетчики samples + uptime, вы можете иметь лучшую эвристику в отношении использования данных...
чтобы добавить к принятому ответу, важно понимать, что объем данных, отображаемых интерфейсом, переполняется и перезапускается на 0 после каждых 4 ГБ, особенно если вы используете этот код для вычисления разницы между двумя показаниями. Это связано с тем, что ifi_obytes и ifi_ibytes являются uint_32, а их максимальное значение равно 4294967295.
кроме того, я рекомендую использовать unsigned ints для переменных, содержащих отправленные и полученные данные. Регулярные ints имеют половину максимального значения целое число без знака, поэтому при добавлении ifi_obytes это может вызвать переполнение.
unsigned int sent = 0; sent += networkStatisc->ifi_obytes;
я исправил выше исходный код для Swift3 версии
struct DataUsageInfo { var wifiReceived: UInt32 = 0 var wifiSent: UInt32 = 0 var wirelessWanDataReceived: UInt32 = 0 var wirelessWanDataSent: UInt32 = 0 mutating func updateInfoByAdding(_ info: DataUsageInfo) { wifiSent += info.wifiSent wifiReceived += info.wifiReceived wirelessWanDataSent += info.wirelessWanDataSent wirelessWanDataReceived += info.wirelessWanDataReceived } } class DataUsage { private static let wwanInterfacePrefix = "pdp_ip" private static let wifiInterfacePrefix = "en" class func getDataUsage() -> DataUsageInfo { var ifaddr: UnsafeMutablePointer<ifaddrs>? var dataUsageInfo = DataUsageInfo() guard getifaddrs(&ifaddr) == 0 else { return dataUsageInfo } while let addr = ifaddr { guard let info = getDataUsageInfo(from: addr) else { ifaddr = addr.pointee.ifa_next continue } dataUsageInfo.updateInfoByAdding(info) ifaddr = addr.pointee.ifa_next } freeifaddrs(ifaddr) return dataUsageInfo } private class func getDataUsageInfo(from infoPointer: UnsafeMutablePointer<ifaddrs>) -> DataUsageInfo? { let pointer = infoPointer let name: String! = String(cString: pointer.pointee.ifa_name) let addr = pointer.pointee.ifa_addr.pointee guard addr.sa_family == UInt8(AF_LINK) else { return nil } return dataUsageInfo(from: pointer, name: name) } private class func dataUsageInfo(from pointer: UnsafeMutablePointer<ifaddrs>, name: String) -> DataUsageInfo { var networkData: UnsafeMutablePointer<if_data>? var dataUsageInfo = DataUsageInfo() if name.hasPrefix(wifiInterfacePrefix) { networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self) if let data = networkData { dataUsageInfo.wifiSent += data.pointee.ifi_obytes dataUsageInfo.wifiReceived += data.pointee.ifi_ibytes } } else if name.hasPrefix(wwanInterfacePrefix) { networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self) if let data = networkData { dataUsageInfo.wirelessWanDataSent += data.pointee.ifi_obytes dataUsageInfo.wirelessWanDataReceived += data.pointee.ifi_ibytes } } return dataUsageInfo } }
Swift версия принятого ответа. Я также разбиваю код на более мелкие единицы.
struct DataUsageInfo { var wifiReceived: UInt32 = 0 var wifiSent: UInt32 = 0 var wirelessWanDataReceived: UInt32 = 0 var wirelessWanDataSent: UInt32 = 0 mutating func updateInfoByAdding(info: DataUsageInfo) { wifiSent += info.wifiSent wifiReceived += info.wifiReceived wirelessWanDataSent += info.wirelessWanDataSent wirelessWanDataReceived += info.wirelessWanDataReceived } } class DataUsage { private static let wwanInterfacePrefix = "pdp_ip" private static let wifiInterfacePrefix = "en" class func getDataUsage() -> DataUsageInfo { var interfaceAddresses: UnsafeMutablePointer<ifaddrs> = nil var dataUsageInfo = DataUsageInfo() guard getifaddrs(&interfaceAddresses) == 0 else { return dataUsageInfo } var pointer = interfaceAddresses while pointer != nil { guard let info = getDataUsageInfo(from: pointer) else { pointer = pointer.memory.ifa_next continue } dataUsageInfo.updateInfoByAdding(info) pointer = pointer.memory.ifa_next } freeifaddrs(interfaceAddresses) return dataUsageInfo } private class func getDataUsageInfo(from infoPointer: UnsafeMutablePointer<ifaddrs>) -> DataUsageInfo? { let pointer = infoPointer let name: String! = String.fromCString(infoPointer.memory.ifa_name) let addr = pointer.memory.ifa_addr.memory guard addr.sa_family == UInt8(AF_LINK) else { return nil } return dataUsageInfo(from: pointer, name: name) } private class func dataUsageInfo(from pointer: UnsafeMutablePointer<ifaddrs>, name: String) -> DataUsageInfo { var networkData: UnsafeMutablePointer<if_data> = nil var dataUsageInfo = DataUsageInfo() if name.hasPrefix(wifiInterfacePrefix) { networkData = unsafeBitCast(pointer.memory.ifa_data, UnsafeMutablePointer<if_data>.self) dataUsageInfo.wifiSent += networkData.memory.ifi_obytes dataUsageInfo.wifiReceived += networkData.memory.ifi_ibytes } else if name.hasPrefix(wwanInterfacePrefix) { networkData = unsafeBitCast(pointer.memory.ifa_data, UnsafeMutablePointer<if_data>.self) dataUsageInfo.wirelessWanDataSent += networkData.memory.ifi_obytes dataUsageInfo.wirelessWanDataReceived += networkData.memory.ifi_ibytes } return dataUsageInfo } }
новая версия о основана на предыдущих версиях, но адаптирована для Swift4 и Xcode 9
struct DataUsageInfo { var wifiReceived: UInt32 = 0 var wifiSent: UInt32 = 0 var wirelessWanDataReceived: UInt32 = 0 var wirelessWanDataSent: UInt32 = 0 mutating func updateInfoByAdding(info: DataUsageInfo) { wifiSent += info.wifiSent wifiReceived += info.wifiReceived wirelessWanDataSent += info.wirelessWanDataSent wirelessWanDataReceived += info.wirelessWanDataReceived } } class DataUsage { private static let wwanInterfacePrefix = "pdp_ip" private static let wifiInterfacePrefix = "en" class func getDataUsage() -> DataUsageInfo { var interfaceAddresses: UnsafeMutablePointer<ifaddrs>? = nil var dataUsageInfo = DataUsageInfo() guard getifaddrs(&interfaceAddresses) == 0 else { return dataUsageInfo } var pointer = interfaceAddresses while pointer != nil { guard let info = getDataUsageInfo(from: pointer!) else { pointer = pointer!.pointee.ifa_next continue } dataUsageInfo.updateInfoByAdding(info: info) pointer = pointer!.pointee.ifa_next } freeifaddrs(interfaceAddresses) return dataUsageInfo } private class func getDataUsageInfo(from infoPointer: UnsafeMutablePointer<ifaddrs>) -> DataUsageInfo? { let pointer = infoPointer let name: String! = String(cString: infoPointer.pointee.ifa_name) let addr = pointer.pointee.ifa_addr.pointee guard addr.sa_family == UInt8(AF_LINK) else { return nil } return dataUsageInfo(from: pointer, name: name) } private class func dataUsageInfo(from pointer: UnsafeMutablePointer<ifaddrs>, name: String) -> DataUsageInfo { var networkData: UnsafeMutablePointer<if_data>? = nil var dataUsageInfo = DataUsageInfo() if name.hasPrefix(wifiInterfacePrefix) { networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self) dataUsageInfo.wifiSent += networkData?.pointee.ifi_obytes ?? 0 dataUsageInfo.wifiReceived += networkData?.pointee.ifi_ibytes ?? 0 } else if name.hasPrefix(wwanInterfacePrefix) { networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self) dataUsageInfo.wirelessWanDataSent += networkData?.pointee.ifi_obytes ?? 0 dataUsageInfo.wirelessWanDataReceived += networkData?.pointee.ifi_ibytes ?? 0 } return dataUsageInfo } }