Как реализовать таймаут для сокета? - PullRequest
2 голосов
/ 01 июля 2010

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

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

Когда я создаю сокет, я регистрирую обратный вызов, который вызывается при поступлении данных, этот обратный вызов должен прослушиваться в фоновом режиме, но я заметил, что если я отправляю данные,и приостановить основной поток приложения (приостановить его на некоторое время или с помощью функции сна), обратный вызов никогда не вызывается.

Поскольку я не могу сделать ожидание в главном потоке, я решил создатьотдельный поток, в этом потоке я сплю в течение определенного времени (тайм-аут), и после этого я проверяю флаг tЭто значение устанавливается только в том случае, если вызывается метод обратного вызова (другими словами, если сервер отправляет мне ответ), и если этот флаг не установлен, то я знаю запрос на тайм-аут сервера и могу двигаться вперед.

Теперь проблема в том, что у меня есть методы, которые отправляют 50 запросов на сервер, логика выглядит следующим образом:

  1. method1 отправляет запрос и запускает ожидающий поток (для проверки таймаута)

  2. ожидающий поток спит в течение n секунд

  3. a - если данные поступают, когда ожидающий поток находится в спящем режиме, вызывается метод обратного вызова, задайтефлаг, указывающий, что данные поступили, выполните некоторые действия и вызовите method1, и цикл начинается с

    b - если данные не поступают, флаг поступивших данных остается ложным

  4. ожидающий поток просыпается, проверьте наличие флага прибывающих данных

    a - если флаг верен (данные получены), выйдите из потока

    b - если флаг ложен (данныене прибыл), вызвать method1 и выйти из потока

Но работа таким образом создает много проблем для моего приложения, не ведет себя должным образом, и иногда это портит вызовы, и во время отладки я вижу, что поток задержки вызывается многимивремя от времени, когда он должен вызываться только один раз в каждом цикле (вы можете думать о цикле, как переход от 1 к 4, см. выше), поэтому я предполагаю, что причина моих проблем заключается в том, как яя использую время ожидания, потому что, если я попытаюсь выполнить команду, которая всегда отправляет ответ, у меня не возникнет никаких проблем.

Кто-нибудь может мне помочь с лучшим способом реализовать ожидание ожидания?

Спасибо.

1 Ответ

2 голосов
/ 12 октября 2010

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

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

Итак, в основном я и сделал, так как мой цикл выполнения никогда не заканчивался после потребления все время, я добавил таймер в цикл выполнения, когда время истекает, он вызывает методы с использованием селектора, и этот метод устанавливает значение флага тайм-аута и как объяснено в одном из ответов из поста, потому что я использую селектор, когда я изменяю значение переменной флага, цикл выполнения немедленно замечает его и завершает работу while.

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

Вот код, который я использовал:

- (IBAction)someRandomAction:(id)sender
{
    Byte byteData[3];    
    int len = 3;
    byteData[0] = 0;
    byteData[1] = 0;
    byteData[2] = 0;
    CFDataRef refData = CFDataCreate(kCFAllocatorDefault, byteData, len);
    timeOut = socketsLibrary.dataArribal = NO;
    [socketsLibrary sendMessage:refData withTag:0];

    NSDate* futureDate = [NSDate dateWithTimeIntervalSinceNow:5.0];    
    NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:futureDate                        
                                                interval:0.1                        
                                                  target:self                        
                                                selector:@selector(wakeUpMainThreadRunloop:)                        
                                                userInfo:nil                        
                                                repeats:NO];
    [[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode];

    while (!timeOut && !socketsLibrary.dataArribal && [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:futureDate]){}

// do something with the data you expect to receive

}

- (void) wakeUpMainThreadRunloop:(id)arg
{
    // This method is executed on main thread!
    // By having it run will
    // make sure the main thread stops running the runloop
    timeOut = YES;
}

В этом коде флаг dataArribal находится внутри socketsLibrary, когда данные поступают с удаленного хоста и вызывается обратный вызов, он также вызывает метод с использованием селектора, и внутри этого метода я делаю:

dataArribal = YES;

Поэтому, когда данные обработаны, этот флаг завершит цикл выполнения.

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