objective-c - 如何实现socket超时?

标签 objective-c iphone sockets timeout

我一直在开发一个适用于 iPad 的应用程序,该应用程序使用套接字与另一个应用程序进行通信,但我在弄清楚如何在向服务器应用程序发送数据时实现超时时遇到了很多问题。

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

当我创建套接字时,我注册了一个回调,当数据到达时调用该回调,这个回调应该在后台监听,但是我注意到,如果我发送数据,并暂停应用程序的主线程(暂停它)使用 while 或使用 sleep 函数)回调永远不会被调用。

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

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

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

  2. 等待线程休眠 n 秒

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

    b - 如果数据数据未到达,则数据到达标志保持 false

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

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

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

但是以这种方式工作会给我的应用程序带来许多问题,表现不正常,有时它会搞乱调用,并且我可以在调试时看到延迟线程在应该的时候连续调用了多次在每个周期中仅被调用一次(您可以认为是从 1 到 4 的周期,请参见上文),所以我的猜测是,我的问题的原因是我实现超时的方式,因为如果我尝试使用始终发送响应的命令,没有遇到任何问题。

有人可以帮助我更好的方法来实现等待超时吗?

谢谢。

最佳答案

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

所以我继续阅读,我注意到帖子中的答案之一提到了研究运行循环的观察者,现在,这对我没有多大帮助,但是在阅读有关观察者的内容时,我遇到了 timers .

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

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

关于objective-c - 如何实现socket超时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3160137/

相关文章:

iOS:dyld:未加载库:@rpath/CocoaLumberjack.framework/CocoaLumberjack

ios - 如何在 iOS 中获取基本的通话、消息和数据使用统计信息?

iphone - QuickDialog 的多行内联条目元素

iphone - 当我尝试从最近的应用程序栏终止我的应用程序时,我的模拟器崩溃了

c++ - 制作 TCP/IP 数据包

c - 如何在c中的UDP套接字中设置源端口?

objective-c - Swift 模块不使用 L10N 中的本地化内容

objective-c - 什么更快 : '-isKindOfClass:' or '-isEqualToString:' ?

iphone - 用于音频和视频组合的 AVCaptureSession - 音频部分提供 EXC_BAD_ACCESS

java - 从套接字的输入流中读取而无需在 JAVA 中忙等待