如何实现套接字超时?

Posted

技术标签:

【中文标题】如何实现套接字超时?【英文标题】:How to implement timeout for socket? 【发布时间】:2010-07-01 17:20:00 【问题描述】:

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

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

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

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

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

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

    等待线程休眠 n 秒

    a - 如果等待线程休眠时数据到达,则调用回调方法,设置数据已到达的标志,做一些事情并调用method1,然后循环重新开始

    b - 如果数据数据没有到达,数据到达标志保持为假

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

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

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

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

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

谢谢。

【问题讨论】:

【参考方案1】:

今天又要面对这个问题,我是通过这个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;

所以当数据处理完毕后,这个标志将使运行循环结束。

【讨论】:

以上是关于如何实现套接字超时?的主要内容,如果未能解决你的问题,请参考以下文章

select() 是不是可以实现单套接字读/写超时?

如何为默认的swagger android客户端设置连接和套接字超时

如何配置套接字连接超时

如何配置套接字连接超时

Java:如何使用“资源尝试”设置套接字超时

如何在 boost asio 中设置阻塞套接字的超时时间?