V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
feng32
V2EX  ›  程序员

基于 poll 的服务器程序如何实现请求超时

  •  
  •   feng32 · 2016-06-17 11:23:39 +08:00 · 2706 次点击
    这是一个创建于 3082 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如果源请求是通过 pollin 获取的,然后把请求丢到一个线程池去处理,在每个线程内部处理超时,这个是比较容易实现的


    现在的场景是,源请求是通过 pollin 获取的,服务器同时还维护一个 socket 池,因此总共需要 poll N + 1 个 socket ;对于每一个源请求,需要检查这个 socket 池中的对应项有没有 pollin 事件:

    • 如果有 pollin 事件,则立即返回收到的 byte arrey
    • 如果没有 pollin 事件,则一直等到主循环检测到 socket 池中的对应项有 pollin 事件再返回

    在这种模式下,万一有个源请求等了一个小时也没有应答也是有可能的,所以最好设置一个超时


    但是 poll 是 I/O 事件驱动的,超时不是一种事件,所以感觉要实现的话比较别扭,我能想到的一个方法是这样的:

    • 对于 socket 池中的每一个 socket ,设置一个时间标记,比如 -1 表示暂时没有请求, 1466133367 表示有请求,并且如果在这个时间后还没 pollin 事件就超时,返回一个空结果;这种情况下,主循环每跑一次就需要扫描一遍这个时间标记列表 (所以 revents 检测加上 timeout 检测总共需要扫两遍)

    还想到一个方法是这样的:

    • 另外建立一个线程,专门记录每个请求的超时时间是多少,一旦发生超时就向主循环发送一个消息告诉它某个请求已经超时了,应该返回个空结果

    感觉这两种方法都不是特别理想,请问这类问题通常的解法是什么?

    5 条回复    2016-06-17 14:40:21 +08:00
    fcicq
        1
    fcicq  
       2016-06-17 11:51:13 +08:00
    你想到的第一个解法换成优化的数据结构就可以了. timer wheel
    sen506
        2
    sen506  
       2016-06-17 11:53:30 +08:00 via Android
    维护一个超时事件堆 socket 入池同时加入超时事件, pollin 触发后重新更新触发事件的 socket 的超时时间, 每次从堆中取出一个超时时间,每次 poll 的超时时间为从堆中取出的那个时间
    sen506
        3
    sen506  
       2016-06-17 12:11:46 +08:00 via Android
    补充下,每次 poll 事件触发后,检查下堆顶,就可以知道是否有 socket 超时了,
    ryd994
        4
    ryd994  
       2016-06-17 12:47:23 +08:00
    维护一个超时堆,按超时时间排序,这样每次遍历只要按顺序查询,不需要扫全表。
    k9982874
        5
    k9982874  
       2016-06-17 14:40:21 +08:00
    记一个动作时间,在你的主循环里检查一下是否超时就行。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2604 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 00:32 · PVG 08:32 · LAX 16:32 · JFK 19:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.