NSURLConnection запускается много раз - PullRequest
7 голосов
/ 20 мая 2009

Я подключаюсь асинхронно с сервером каждые 5 секунд. URL-адрес тот же, но POST-тело меняется каждый раз. Теперь я каждый раз создаю NSURL, NSURLRequest и NSURLConnection с нуля.

Я думаю, что было бы эффективнее установить соединение один раз и просто использовать его еще раз. Я новичок и не уверен, что это возможно. Изменяемого NSURLConnection не существует, но может потребоваться создать NSURLConnection, например:

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

и измените POST-данные NSMutableURLRequest для отправки еще одного запроса на сервер. Какой путь правильный?

Ответы [ 4 ]

10 голосов
/ 20 мая 2009

Полагаю, что вас беспокоит, это издержки создания HTTP-соединения. NSURLConnection достаточно умен, чтобы справиться с этим с помощью HTTP / 1.1 и повторного использования существующих соединений. В прошлый раз, когда я проверял, он не использует конвейеризацию, но для вашей цели достаточно повторного использования соединения. Я призываю вас включить сетевой сниффер и убедиться, что он работает так, как вы хотите.

Стоимость создания самих объектов тривиальна, примерно раз в 5 с, и вы не должны пытаться оптимизировать это (хотя, конечно, вам следует повторно использовать NSURL). Это дорогое подключение к серверу, особенно на iPhone.

Если вы обнаружите, что действительно нуждаетесь в конвейерной обработке, вам, к сожалению, придется свернуть свою собственную. Я слышал, что CFHTTPStream может это сделать, но я не вижу много доказательств этого. CocoaAsyncSocket - ваш лучший выбор для низкоуровневого доступа к сокетам без необходимости писать низкоуровневый код.

Поскольку задержка в сотовой сети может быть очень плохой, возможно, ваше соединение займет больше 5 секунд. Убедитесь, что одно соединение установлено, прежде чем начинать следующее, иначе вы начнете создавать все больше и больше открытых соединений.

6 голосов
/ 30 апреля 2012

Просто чтобы прояснить ситуацию, NSURLConnection будет повторно использовать существующие сокеты, но только в течение относительно небольшого периода времени (12 секунд). Если вы отправляете запрос, получаете ответ и отправляете последующий запрос в течение 12 секунд, чтобы второй запрос поступил в тот же сокет. В противном случае сокет будет закрыт клиентом. Apple подала ошибку, чтобы увеличить этот таймер или сделать его настраиваемым.

3 голосов
/ 06 мая 2013

@ Роб Нейпир @ Эрик Нельсон Как вы упомянули: «NSURLConnection достаточно умен, чтобы справиться с этим с помощью HTTP / 1.1 и повторного использования существующих соединений». Однако я не могу найти такое описание ни в одном документе Apple об этом.

Чтобы прояснить ситуацию, я пишу код для проверки:

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

И затем я запускаю wireshark для перехвата пакетов на сервере (192.168.1.xxx), используя "(tcp.flags.syn == 1) || (tcp.flags == 0x0010 && tcp.seq == 1 && tcp.ack == 1) "для фильтрации tcp трехстороннего дрожания рук. К сожалению, я вижу трёхстороннее дрожание рук для каждого вызова «sendOneRequest». Это означает, что NSURLConnection, похоже, не использует существующие соединения. Кто-нибудь может указать, что не так в моем коде и как отправить несколько запросов через одно сокетное соединение NSURLConnection?

Я также пытался синхронно отправить запрос:

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

}

И результат тот же.

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

Наконец, я нашел причину, по которой мой тест отличается от того, что говорят Роб и Эрик. Короче говоря, Роб и Эрик правы. А NSURLConnection по умолчанию использует «keep-alive» для использования HTTP / 1.1 и повторно использует существующее сокетное соединение, но только в течение относительно небольшого периода времени.

Тем не менее, NSURLConnection имеет некоторые проблемы для «кусочного кодирования передачи» (т. Е. Без длины контента).

В моем тесте серверная сторона отправляет ответ без длины содержимого и данных ответа, а ответ по частям и NSURLConnection закрывает соединение, таким образом, для каждого сообщения http происходит трехстороннее рукопожатие.

Я изменил свой серверный код, установил длину ответа равной 0, и поведение верное.

0 голосов
/ 20 мая 2009

сделать метод, который возвращает запрос и сделать

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

...