当服务器没有响应时,在Python中中止GET请求

时间:2015-08-13 21:06:00

标签: python http get long-polling

我在Python中实现了HTTP长轮询器。简单来说,它是一个程序,它定期连接到服务器并使用GET请求检索一些信息。 长轮询技术与“正常”轮询不同,因为如果服务器收到请求并且没有新数据,则不等待发送空响应,而是等待新数据变为可用,从而使请求保持打开状态。

基本上,当我向此服务器发出请求时,它可能会立即向我发送回复,或者它可能会让我的GET开放几分钟。

一切正常,当我希望程序关闭时,问题就出现了。我已经尝试了urllib3requests个模块,如果有挂起的请求,他们就不会让我的程序关闭。

所以,我的问题是,当服务器没有响应时(使用提到的模块),是否有一种方法可以中止GET请求。 在这些情况下,设置超时可以解决我的问题,但在这种特定情况下显然是不可能的。

一个解决方案可能是将请求放在一个线程中并在程序关闭时将其终止,但是杀死一个线程不是一个好习惯。 也许有一个更明确的模块来实现长轮询?

2 个答案:

答案 0 :(得分:4)

您可以使用requests的简单try-except块:

try:
    r = requests.get(url, timeout=5)
except requests.exceptions.RequestException as e:
    print(e)
    continue

编辑添加超时参数。

答案 1 :(得分:1)

我建议你在一个帖子中使用urllib2(我没有看到任何其他方式),然后在等待响应时关闭连接。

其他方式都可以解决问题但不是你想要的意义。

一个是您总是从服务器返回数据,但是当您没有要返回的信息时,返回一些消息,指示客户端应该稍后再次检查。

你提到的就是杀死线程,但是,这不是一个很好的解决方案。

我建议关闭与服务器的连接并等待它中断:

from urllib2 import urlopen
from thread import start_new_thread as thread
from time import sleep

class Req:
    def __init__ (self, url, callback=lambda: None):
        self.polled_conn = None
        self.url   = url
        self.data  = None
        self.error = None
        self.callback = callback
        self.cancelled = 0
        self.polling = 0

    def poll (self):
        thread(self._poll,())

    def get (self):
        self.data  = None
        self.error = None
        cb = self.callback
        self.callback = lambda: None
        thread(self._poll,())
        while self.data==None and self.error==None: sleep(0.001)
        self.callback = cb
        if self.error: raise self.error
        return self.data

    def _poll (self):
        if self.polling: return
        self.polling = 1
        self.data  = None
        self.error = None
        self.cancelled = 0
        try:
            self.polled_conn = u = urlopen(self.url)
        except Exception, e: self.error = e; self.polling = 0; return self.callback()
        try:
            self.data = u.read()
        except AttributeError, e:
            if "recv" in str(e): self.cancelled = 1; self.polling = 0; return # Receiving aborted!
            else: self.error = e
        except IOError, e: self.cancelled = 1; self.polling = 0; return # Receiving aborted
        except Exception, e: self.error = e
        self.polling = 0
        self.callback()

    def cancel (self):
        if self.polled_conn:
            self.polled_conn.close()

    def iscancelled (self): return self.cancelled

通过get()方法提供了一些用法,但是你有更多的可能性。 使用get(),您可以获得标准的数据阻塞返回:

r = Req("http://example.com")
data = r.get()
print data

要实现您的目标,您可以在此处指定回调并使用它来处理数据,在程序退出时您可以取消任何待处理的转移:

def oncallback ():
    if r.data!=None:
        print len(r.data), r.data[:100]
    else: raise r.error
    sleep(1)
    r.poll() # Poll again for new info

r = None
def start ():
    global r
    r = Req("http://example.com", oncallback)
    r.poll()

start()
raw_input() # Wait for enter to close
r.cancel()
print "Cancelling"
if r.polling:
    while not r.iscancelled(): sleep(0.001)
print "Ready to close!"
# You can set r.polling to 1, to prevent the callback to poll again in midle of shutdown
#r.polling = 1 # Dirty trick
# Using threading module would make things just a little easier

或者你仍然可以在没有回调的情况下(类似异步):

running = 1
r = Req("http://example.com")
r.poll()
while running:
    if r.error!=None:
        print r.error
        # Decide what to do according to this error
        #if not isinstance(r.error, URLError): r.poll() # or something
        continue
    if r.data==None: sleep(0.001); continue # Do something anyway while waiting for data
    # Data arrived so:
    print data[:100] # Do some stuff
    r.poll() # Poll again for new
    # Somewhere here check whether user wants to close a program and then
    #running = 0 or break

r.cancel()
if r.polling:
    while not r.iscancelled(): sleep(0.001)

这对我来说很有效。用于挂起连接或正在进行的传输。 可能仍有一些警告或错误,更好的说错误,以解决。