Длительный опрос в объективе-C

У меня есть приложение, которое использует API для получения обновлений в реальном времени на веб-сайте. Они используют то, что называют техникой длинных опросов:

Длинный опрос является разновидностью традиционной техники опроса и позволяет эмулировать передачу информации с сервера на клиент. При длительном опросе клиент запрашивает информацию с сервера аналогично обычному опросу. Однако, если на сервере нет какой-либо информации, доступной для клиента, вместо отправки пустого ответа сервер удерживает запрос и ожидает, пока некоторая информация не станет доступной. Как только информация становится доступной (или по истечении подходящего времени ожидания), полный ответ отправляется клиенту. Затем клиент обычно немедленно повторно запрашивает информацию с сервера, так что сервер почти всегда будет иметь доступный ожидающий запрос, который он может использовать для доставки данных в ответ на событие. В контексте web/AJAX длинный опрос также известен как программирование Comet.

Длинный опрос сам по себе не является технологией push, но может использоваться в условиях, когда настоящий push-запрос невозможен.

По сути, это заставляет отправлять запрос обратно на сервер после получения ответа. Каков наилучший способ сделать это в приложении для iPhone? Это в конечном итоге должно работать в фоновом режиме.

2 ответа

Решение

Это именно тот вариант использования, который NSURLConnection sendSynchronousRequest идеально подходит для:

- (void) longPoll {
    //create an autorelease pool for the thread
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    //compose the request
    NSError* error = nil;
    NSURLResponse* response = nil;
    NSURL* requestUrl = [NSURL URLWithString:@"http://www.mysite.com/pollUrl"];
    NSURLRequest* request = [NSURLRequest requestWithURL:requestUrl];

    //send the request (will block until a response comes back)
    NSData* responseData = [NSURLConnection sendSynchronousRequest:request
                            returningResponse:&response error:&error];

    //pass the response on to the handler (can also check for errors here, if you want)
    [self performSelectorOnMainThread:@selector(dataReceived:) 
          withObject:responseData waitUntilDone:YES];

    //clear the pool 
    [pool drain];

    //send the next poll request
    [self performSelectorInBackground:@selector(longPoll) withObject: nil];
}

- (void) startPoll {
    //not covered in this example:  stopping the poll or ensuring that only 1 poll is active at any given time
    [self performSelectorInBackground:@selector(longPoll) withObject: nil];
}

- (void) dataReceived: (NSData*) theData {
    //process the response here
}

С другой стороны, вы можете использовать асинхронный ввод-вывод и делегировать обратные вызовы для выполнения той же задачи, но в этом случае это будет довольно глупо.

При длительном опросе выполняется запрос на чтение к серверу, сервер получает запросы, обнаруживает, что отправлять вам ничего интересного, и вместо того, чтобы ничего не возвращать или "пустой", вместо этого он удерживает запрос, пока не появится что-то интересное., Как только он что-то находит, он пишет в сокет, и клиент получает данные.

Суть в том, что за все это время, используя универсальное программирование сокетов, клиент блокируется и висит на вызове чтения сокетов.

Есть два способа справиться с этим (ну, три, если вы не против застрять в главном потоке на несколько секунд, но давайте не будем считать это).

  1. Поместите код обработки сокета в поток. В этом случае весь процесс сокета находится в независимом потоке в программе, поэтому он с радостью застрял в чтении, ожидая ответа.

  2. Используйте асинхронную обработку сокетов. В этом случае чтение из вашего сокета НЕ блокирует основной поток. Вместо этого вы передаете функции обратного вызова, которые реагируют на активность в сокете, и затем продолжаете свой веселый путь. На Mac есть CFSocket, который предоставляет такую ​​функциональность. Он порождает свой собственный поток и управляет соединением сокетов, используя select(2).

Это хороший небольшой пост, рассказывающий о CFSocket.

CFSocket хорошо вписывается в идиому Mac для передачи сообщений и обработки событий, и, вероятно, именно на это следует обратить внимание при выполнении этой работы. Существует также оболочка класса Obj-C, построенная на CFSocket, которая называется ULNetSocket (ранее NetSocket).

Другие вопросы по тегам