如何实现socket的超时?

时间:2010-07-01 17:20:00

标签: objective-c iphone sockets timeout

我一直致力于使用套接字与其他应用程序进行通信的iPad应用程序,并且在将数据发送到服务器应用程序时,如何实现超时时遇到很多问题。

我喜欢发送到服务器的3个命令,具体取决于我需要的信息类型,其中一个命令总是发送响应,但其他2个没有,所以我需要在我的应用程序中超时才能知道当服务器没有发送响应时。

当我创建套接字时,我注册了一个在数据到达时调用的回调,这个回调应该在后台监听,但我注意到如果我发送数据,并暂停应用程序的主线程(暂停它)有一段时间或有睡眠功能)从不调用回调。

由于我无法在主线程中等待,我决定创建一个单独的线程,在这个线程中,我所做的是将线程休眠一段时间(超时),之后我检查一个仅在调用回调方法时设置的标志(换句话说,如果服务器向我发送响应),并且如果未设置此标志,那么我知道对服务器的请求超时,我可以继续前进。

现在,问题是我有向服务器发送50个请求的方法,逻辑如下:

  1. method1发送请求并启动等待线程(检查超时)

  2. 等待线程休眠n秒

  3. a - 如果数据在等待线程休眠时到达,则调用回调方法,设置指示数据已到达的标志,执行一些操作并调用method1,并重新开始循环

    b - 如果数据数据未到达,则数据到达标志仍然为假

  4. 等待线程唤醒,检查数据到达标志

    a - 如果标志为真(数据到达),退出线程

    b - 如果标志为假(数据未到达),则调用method1,然后退出线程

  5. 但是以这种方式工作会给我的应用程序带来很多问题,行为不正常,有时会搞乱调用,我可以在调试时看到延迟线程被连续多次调用,什么时候应该调用在每个循环中只调用一次(你可以想到一个循环,比如从1到4,见上文),所以我的猜测是我的问题的原因是我实现超时的方式,因为如果我尝试使用总是发送响应的命令,我没有任何麻烦。

    有没有人可以帮助我更好地实现等待超时?

    感谢。

1 个答案:

答案 0 :(得分:2)

今天我不得不再次面对这个问题,我来到这里post;这是我打算用来解决上面描述的问题的方法,但由于某种原因,即使消耗了时间间隔,while循环也从未在我的应用程序中结束。

所以我继续阅读,我注意到帖子中提到的一个答案正在查看运行循环的观察者,现在,这对我没什么帮助,但在阅读观察者时我碰到了timers

所以,基本上我所做的是,因为我的运行循环在消耗所有时间后从未结束,我在运行循环中添加了一个计时器,当计时器到期时,它使用选择器调用方法,并且该方法设置值一个超时标志,并在帖子的一个答案中解释,因为我正在使用一个选择器,当我更改标志变量的值时,运行循环立即注意到它,然后退出。

这种方法的优点在于应用程序不会被阻止,因此从服务器侦听数据的回调可以完成它的工作。

以下是我使用的代码:

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

因此,当处理数据时,此标志将使运行循环完成。