Monitoraggio / monitoraggio dell'utilizzo dei dati di iPhone


136

Ho cercato su questo argomento ma ho trovato pochissimi dettagli che sono stati utili. Con questi dettagli ho provato a cucinare un po 'di codice come segue.

Nota: si prega di confrontare i dettagli condivisi in questo post con altri post prima di contrassegnarli come DUPLICATE e non solo per argomento.

- (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];    
}

Questo codice raccoglie informazioni sull'uso di Internet di un dispositivo iPhone (e non solo sulla mia applicazione).

Ora, se uso Internet tramite WiFi o 3G, ottengo i dati (byte) solo in ifi_obytes(inviati) e ifi_ibytes(ricevuti) ma penso che dovrei ottenere l'utilizzo del WiFi in ifi_opacketse ifi_ipackets.

Volevo anche aggiungere che se sono connesso a una rete WiFi, ma non utilizzo Internet, ottengo ancora valore aggiunto a ifi_obytese ifi_ibytes.

Potrei sbagliarmi nell'attuazione o nella comprensione. Ho bisogno di qualcuno che mi aiuti.


Modifica: Invece di AF_LINKho provato AF_INET( sockaddr_ininvece di sockaddr_dl). Questo arresta in modo anomalo l'applicazione.

Risposte:


175

Il fatto è che pdp_ip0è una delle interfacce, tutte pdpXXXsono WWANinterfacce dedicate a diverse funzioni, posta vocale, interfaccia di rete generale.

Ho letto nel forum Apple che: Il sistema operativo non mantiene le statistiche di rete su una base processo per processo. Pertanto, non esiste una soluzione esatta a questo problema. Tuttavia, è possibile ottenere statistiche di rete per ciascuna interfaccia di rete.

In generale en0è la tua Wi-Fiinterfaccia ed pdp_ip0è la tua WWANinterfaccia.

Non esiste un buon modo per ottenere informazioni sui dati della rete wifi / cellulare da allora, data-ora particolare!

Le statistiche sui dati ( ifa_data->ifi_obytese ifa_data->ifi_ibytes) vengono archiviate dal precedente riavvio del dispositivo.

Non so perché, ma ifi_opacketse ifi_ipacketsvengono visualizzate le solo per lo0(credo che la sua interfaccia principale).

Sì. Quindi il dispositivo è collegato tramite WiFie non utilizza if_iobytesancora i valori di Internet perché questo metodo fornisce scambi di byte di rete e non solo Internet.

#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)};
}

Supporto copia / incolla migliorato!


1
Molte grazie. Questo codice ha funzionato a meraviglia. Grazie anche per aver spiegato le cose.
Sahil Khanna,

20
Devi importare queste librerie: #include <arpa / inet.h> #include <net / if.h> #include <ifaddrs.h> #include <net / if_dl.h>
user982705

9
È possibile con questo codice tenere traccia del traffico dati per applicazione iOS?
fvisticot,

2
@Mat: la soluzione che ho progettato per i client aziendali e non è distribuita su AppStore.
Sahil Khanna,

4
Qualcuno ha capito come ottenere i dati per app? Condividi il codice per favore :)
Bob de Graaf il

16

È importante capire che questi contatori sono forniti dall'ultimo avvio del dispositivo.

Quindi, per usarli efficacemente, dovresti accompagnare ogni campione con il tempo di attività del dispositivo (puoi usarlo mach_absolute_time()- vedi questo per maggiori informazioni)

Una volta che hai i contatori campioni + tempo di attività puoi avere una migliore euristica sull'uso dei dati ...


mach_absolute_time non è tempo di attività. È approssimativamente la quantità di tempo in cui la CPU è stata attiva. mach_absolute_time smette principalmente di contare quando il dispositivo dorme.
Bob Whiteman,

13

Per aggiungere alla risposta accettata, è importante rendersi conto che la quantità di dati visualizzati dall'interfaccia trabocca e si riavvia in 0seguito 4 GB, soprattutto se si utilizza questo codice per calcolare la differenza tra due letture. Questo perché ifi_obytese lo ifi_ibytessono uint_32e il loro valore massimo è 4294967295.

Inoltre, raccomando di usare unsigned ints per le variabili che contengono i dati inviati e ricevuti. I normali inthanno la metà del valore massimo di un intero senza segno, quindi quando si aggiunge ifi_obytespuò causare un overflow.

unsigned int sent = 0;
sent += networkStatisc->ifi_obytes;

4

Versione rapida della risposta accettata. Inoltre spezzo il codice in unità più piccole.

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
    }
}

4

Ho corretto il codice sorgente sopra alla versione 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
    }
}

4

Una nuova versione basata su versioni precedenti, ma adattata per Swift4 e 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
    }
}

viene visualizzato per ogni app o l'app effettiva in cui viene utilizzata?
Maksim Kniazev

È l'uso globale ... Non è separato dall'app.
dede.exe

E il valore è dall'ultimo riavvio. Non c'è modo di ottenere per il mese passato / corrente?
Slavcho,

@Slavcho. Fino a questa data di pubblicazione non era possibile. Non ho ancora fatto una nuova ricerca al riguardo dopo iOS12. Ti consiglio di accumulare ir in qualche posto per recuperarlo dopo.
dede.exe,

0

Ci scusiamo per la stessa risposta.

ma ho scoperto che UInt32 non è abbastanza, quindi si blocca quando diventa troppo grande.

Ho appena cambiato UInt32 in UInt64 e funziona benissimo.

struct DataUsageInfo {
    var wifiReceived: UInt64 = 0
    var wifiSent: UInt64 = 0
    var wirelessWanDataReceived: UInt64 = 0
    var wirelessWanDataSent: UInt64 = 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 += UInt64(networkData?.pointee.ifi_obytes ?? 0)
            dataUsageInfo.wifiReceived += UInt64(networkData?.pointee.ifi_ibytes ?? 0)
        } else if name.hasPrefix(wwanInterfacePrefix) {
            networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
            dataUsageInfo.wirelessWanDataSent += UInt64(networkData?.pointee.ifi_obytes ?? 0)
            dataUsageInfo.wirelessWanDataReceived += UInt64(networkData?.pointee.ifi_ibytes ?? 0)
        }

        return dataUsageInfo
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.