Длительный опрос в объективе-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
}
С другой стороны, вы можете использовать асинхронный ввод-вывод и делегировать обратные вызовы для выполнения той же задачи, но в этом случае это будет довольно глупо.
При длительном опросе выполняется запрос на чтение к серверу, сервер получает запросы, обнаруживает, что отправлять вам ничего интересного, и вместо того, чтобы ничего не возвращать или "пустой", вместо этого он удерживает запрос, пока не появится что-то интересное., Как только он что-то находит, он пишет в сокет, и клиент получает данные.
Суть в том, что за все это время, используя универсальное программирование сокетов, клиент блокируется и висит на вызове чтения сокетов.
Есть два способа справиться с этим (ну, три, если вы не против застрять в главном потоке на несколько секунд, но давайте не будем считать это).
Поместите код обработки сокета в поток. В этом случае весь процесс сокета находится в независимом потоке в программе, поэтому он с радостью застрял в чтении, ожидая ответа.
Используйте асинхронную обработку сокетов. В этом случае чтение из вашего сокета НЕ блокирует основной поток. Вместо этого вы передаете функции обратного вызова, которые реагируют на активность в сокете, и затем продолжаете свой веселый путь. На Mac есть CFSocket, который предоставляет такую функциональность. Он порождает свой собственный поток и управляет соединением сокетов, используя select(2).
Это хороший небольшой пост, рассказывающий о CFSocket.
CFSocket хорошо вписывается в идиому Mac для передачи сообщений и обработки событий, и, вероятно, именно на это следует обратить внимание при выполнении этой работы. Существует также оболочка класса Obj-C, построенная на CFSocket, которая называется ULNetSocket (ранее NetSocket).