2009-05-20 14 views
7

Me conecto de forma asíncrona con el servidor cada 5 segundos. La URL es la misma, pero POST-body se cambia cada vez. Ahora creo NSURL, NSURLRequest y NSURLConnection desde cero cada vez.NSURLConnection se ejecuta muchas veces

Creo que sería más efectivo establecer la conexión una sola vez y usarla más. Soy un novato y no estoy seguro si eso es posible. No hay ninguna NSURLConnection mutable, pero se puede necesitar para crear NSURLConnection como:

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

y cambiar NSMutableURLRequest de datos posteriores a enviar otra solicitud al servidor. ¿Cuál es el camino correcto?

+0

if (! Conexión) connection = [[NSURLConnection alloc] initWithRequest: request delegate: self startImmediately: NO]; [inicio de la conexión]; Este no funciona, da "EXC_BAD_ACCESS". Busqué foros para eso y no hay respuesta. Parece que 'inicio' es necesario para usar de otra manera. – slatvick

+0

Es una rareza de este método de inicialización que debe programar la conexión en un runloop antes de iniciarlo. –

Respuesta

9

Supongo que lo que le preocupa es la sobrecarga de la creación de la conexión HTTP. NSURLConnection es lo suficientemente inteligente como para manejar esto para usted usando HTTP/1.1 y reutilizar las conexiones existentes. No utiliza el pipeline la última vez que lo verifiqué, pero para su propósito, la reutilización de la conexión debería ser suficiente. Lo aliento a que ponga un sniffer de red sobre esto y se asegure de que está funcionando como usted lo desea.

El costo de creación de los objetos en sí es trivial en el orden de una vez por 5s y no debe tratar de optimizarlo (aunque, por supuesto, debe reutilizar el NSURL). Es la apertura de una conexión al servidor que es costosa, especialmente en iPhone.

Si realmente lo que necesita es la canalización, desafortunadamente tendrá que hacer el suyo propio. Escuché que CFHTTPStream puede hacerlo, pero no veo mucha evidencia de eso. CocoaAsyncSocket es su mejor opción para el acceso de bajo nivel a los sockets sin tener que escribir código de bajo nivel.

Como la latencia en la red de la célula puede ser muy mala, es posible que su conexión tarde más de 5 segundos en completarse. Asegúrate de que se haya realizado una conexión antes de comenzar la siguiente, o comenzarás a hacer más y más conexiones abiertas.

+0

Muchas gracias. Como entiendo, NSURL abre una conexión, ¿verdad? De ser así, no necesito más optimizaciones, solo necesito no abrir la conexión cada 5 segundos, lo cual es bastante costoso, como usted también entiende. – slatvick

+2

NSURL en sí mismo no abre una conexión. Simplemente analiza cadenas. NSURLConnection abre la conexión y maneja la reutilización de la conexión HTTP/1.1 por usted. –

+0

Necesito mantener viva una conexión y cambiar NSMutableURLRequest POST-data para enviar diferentes POST a través de él. ¿Es posible? ¿Cómo? – slatvick

0

crea un método que devuelve una petición y hacer

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

?

+0

[[NSURLConnection alloc] init ...]; crea una nueva conexión cada vez, pero quiero usar una conexión por un tiempo simplemente cambiando los datos POST de una solicitud por: [request setHTTPBody: newRequestData]; – slatvick

6

Solo para aclarar las cosas, NSURLConnection reutilizará los sockets existentes, pero solo para un marco de tiempo relativamente pequeño (12 segundos). Si envía una solicitud, obtenga una respuesta y envíe una solicitud posterior en 12 segundos para que la segunda solicitud se publique en el mismo socket. De lo contrario, el cliente cerrará el socket. Se ha registrado un error con Apple para aumentar este temporizador o hacerlo configurable.

3

@Rob Napier @Eric Nelson Como mencionaste: "NSURLConnection es lo suficientemente inteligente como para manejar esto usando HTTP/1.1 y reutilizando las conexiones existentes". Sin embargo, no puedo encontrar tal descripción en ningún documento de Apple al respecto.

Para hacer algo en claro, que escribir código para probarlo:

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

Y entonces, comienzo Wireshark para capturar paquetes en el servidor (192.168.1.xxx), usando "(tcp.flags .syn == 1) || (tcp.flags == 0x0010 & & tcp.seq == 1 & & tcp.ack == 1) "para filtrar tcp agitador manual de 3 vías. Desafortunadamente, puedo ver el movimiento de manos de 3 vías para cada llamada de "sendOneRequest". Lo que significa que el NSURLConnection parece no reutilizar las conexiones existentes. ¿Puede alguien señalar lo que está mal en mi código y cómo enviar solicitudes múltiples a través de una conexión de socket mediante NSURLConnection?

También probé manera sincrónica a enviar solicitud:

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

} 

y el resultado es el mismo.

======= ACTUALIZACIÓN ============================

Por último, he encontrado la razón por qué mi prueba es diferente de Rob y Eric dicen. En resumen, Rob y Eric están en lo cierto. Y NSURLConnection usa "keep-alive" como predeterminado para usar HTTP/1.1 y reutiliza la conexión de socket existente, pero solo para un marco de tiempo relativamente pequeño.

Sin embargo, NSURLConnection tiene algunos problemas para la "codificación de transferencia fragmentada" (es decir, sin contenido de longitud).

En mi prueba, el lado del servidor envía una respuesta sin contenido de longitud y datos de respuesta, y su respuesta fragmentada y NSURLConnection cerrará la conexión, por lo que se producirá agitación tridireccional de las manos para cada publicación HTTP.

Cambié el código de mi servidor, establecí la duración de la respuesta en 0 y el comportamiento es correcto.

Cuestiones relacionadas