2009-05-20 19 views
7

Mi collego in modo asincrono con il server ogni 5 secondi. L'URL è lo stesso, ma il corpo POST viene cambiato ogni volta. Ora creo NSURL, NSURLRequest e NSURLConnection da zero ogni volta.NSURLConnection viene eseguito più volte

Penso che sarebbe più efficace impostare una connessione e utilizzarla ancora. Sono un principiante e non sono sicuro che sia possibile. Non v'è alcun NSURLConnection mutevole, ma potrebbe è necessario creare NSURLConnection come:

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: url]; 
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 

e cambiare NSMutableURLRequest POST-dati da inviare un'altra richiesta al server. Quale via è giusta?

+0

if (! Connection) connection = [[NSURLConnection alloc] initWithRequest: request delegate: self startImmediately: NO]; [avvio connessione]; Questo non funziona restituisce "EXC_BAD_ACCESS". Ho cercato forum per questo e non c'è risposta. Sembra che "start" sia necessario per usare un altro modo. – slatvick

+0

È una stranezza di questo metodo di inizializzazione che è necessario pianificare la connessione su un runloop prima di avviarlo. –

risposta

9

Presumo che quello che ti preoccupa è il sovraccarico della creazione della connessione HTTP. NSURLConnection è abbastanza intelligente da gestire questo per te usando HTTP/1.1 e riutilizzando le connessioni esistenti. Non usa pipelining l'ultima volta che ho controllato, ma per il tuo scopo, il riutilizzo della connessione dovrebbe essere sufficiente. Vi incoraggio a mettere uno sniffer di rete su questo e assicurarsi che funzioni come volete.

Il costo della creazione degli oggetti stessi è banale nell'ordine di una volta per 5s e non si dovrebbe cercare di ottimizzare tale valore (anche se ovviamente si dovrebbe riutilizzare NSURL). È l'apertura di una connessione al server che è costoso, specialmente su iPhone.

Se ritieni che sia davvero necessario il pipelining, purtroppo dovrai eseguire il rollover. Ho sentito che CFHTTPStream può farlo, ma non ne vedo molte prove. CocoaAsyncSocket è la soluzione migliore per accedere a basso livello ai socket senza dover scrivere codice di basso livello.

Poiché la latenza sulla rete cellulare può essere molto grave, è possibile che la connessione richieda più di 5 secondi per essere completata. Assicurati che sia stata effettuata una connessione prima di iniziare la prossima oppure inizierai a creare connessioni sempre più aperte.

+0

Grazie mille. Come ho capito NSURL apre una connessione, giusto? se è così non ho bisogno di più ottimizzazioni, ho solo bisogno di non aprire la connessione ogni 5 secondi, che è piuttosto costoso, come capisci anche tu. – slatvick

+2

NSURL non apre una connessione. Analizza solo le stringhe. NSURLConnection apre la connessione e gestisce il riutilizzo della connessione HTTP/1.1 per te. –

+0

Devo mantenere una connessione attiva e modificare NSMutableURLRequest I dati POST inviano diversi POST attraverso di essa. È possibile? Come? – slatvick

0

fanno un metodo che restituisce una richiesta e fare

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[self requestMethod] delegate:self]; 

?

+0

[[NSURLConnection alloc] init ...]; crea una nuova connessione ogni volta, ma voglio usare una sola connessione per lungo tempo cambiando solo i dati POST di una richiesta: [richiesta setHTTPBody: newRequestData]; – slatvick

6

Giusto per chiarire le cose, NSURLConnection riutilizzerà le prese esistenti, ma solo per un intervallo di tempo relativamente piccolo (12 secondi). Se si invia una richiesta, ottenere una risposta e inviare una richiesta successiva entro 12 secondi che la seconda richiesta verrà inviata sullo stesso socket. In caso contrario, il socket verrà chiuso dal client. Un bug è stato archiviato con Apple per aumentare questo timer o per renderlo configurabile.

3

@Rob Napier @Eric Nelson Come già menzionato: "NSURLConnection è abbastanza intelligente da gestire ciò per te utilizzando HTTP/1.1 e riutilizzando le connessioni esistenti". Tuttavia, non riesco a trovare una descrizione del genere in nessun documento Apple.

Per fare cosa chiara, ho scrivere del codice per testarlo:

- (IBAction)onClickSend:(id)sender { 
    [self sendOneRequest]; 
} 

-(void)sendOneRequest { 

    NSURL *url = [NSURL URLWithString:@"http://192.168.1.100:1234"]; 
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; 
    [request setHTTPMethod:@"POST"]; 
    [request addValue:[Base64 encodeFromString:kValueVersion] forHTTPHeaderField:kKeyVersion]; 
    [request addValue:[Base64 encodeFromString:kValueDataTypeCmd] forHTTPHeaderField:kKeyDataType]; 
    [request addValue:[Base64 encodeFromString:@"Test"] forHTTPHeaderField:kKeyCmdName]; 
    [request addValue:[Base64 encodeFromString:@"Test"] forHTTPHeaderField:kKeyDeviceName]; 
    [request addValue:[Base64 encodeFromString:@"xxdafadfadfa"] forHTTPHeaderField:kKeyDTLCookies]; 
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 
    [connection start]; 
} 

E poi, comincio Wireshark per catturare i pacchetti sul server (192.168.1.xxx), utilizzando "(tcp.flags .syn == 1) || (tcp.flags == 0x0010 & & tcp.seq == 1 & & tcp.ack == 1) "per filtrare il tremolio della mano a tre vie tcp. Sfortunatamente, posso vedere il tremolio della mano a 3 vie per ogni chiamata di "sendOneRequest". Il che significa che NSURLConnection sembra non riutilizzare le connessioni esistenti. Qualcuno può segnalare cosa c'è di sbagliato nel mio codice e come inviare più richieste tramite una connessione socket tramite NSURLConnection?

Ho anche provato modo sincrono di inviare richiesta:

-(void)sendOneRequest { 
    NSURL *url = [NSURL URLWithString:@"http://192.168.1.100:1234"]; 
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; 
    [request setHTTPMethod:@"POST"]; 
    [request addValue:[Base64 encodeFromString:kValueVersion] forHTTPHeaderField:kKeyVersion]; 
    [request addValue:[Base64 encodeFromString:kValueDataTypeCmd] forHTTPHeaderField:kKeyDataType]; 
    [request addValue:[Base64 encodeFromString:@"Test"] forHTTPHeaderField:kKeyCmdName]; 
    [request addValue:[Base64 encodeFromString:@"Test"] forHTTPHeaderField:kKeyDeviceName]; 
    [request addValue:[Base64 encodeFromString:@"xxdafadfadfa"] forHTTPHeaderField:kKeyDTLCookies]; 

    [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; 

    sleep(1); 

    [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; 

    sleep(1); 

    [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; 

} 

e il risultato è lo stesso.

======= UPDATE ============================

Infine, ho trovato la ragione perché il mio test è diverso da Rob e Eric dicono. In breve, Rob e Eric hanno ragione. E NSURLConnection usa "keep-alive" come predefinito per l'utilizzo di HTTP/1.1 e riutilizza la connessione socket esistente, ma solo per un intervallo di tempo relativamente piccolo.

Tuttavia, NSURLConnection presenta alcuni problemi per "codifica di trasferimento chunked" (cioè senza lunghezza del contenuto).

Nel mio test, il lato server invia una risposta senza dati di lunghezza del contenuto e di risposta, ed è una risposta frammentata e NSURLConnection chiuderà la connessione, quindi si verifica un tremolio della mano a 3 vie per ogni post http.

Ho modificato il mio codice server, impostato la lunghezza della risposta come 0 e il comportamento è corretto.

Problemi correlati