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

标签 python http get long-polling

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

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

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

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

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

最佳答案

我建议您在线程中使用 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)

这非常适合我。用于挂起连接或正在进行的传输。 可能仍然存在一些警告或错误,更确切地说是错误,需要修复。

关于python - 当服务器没有响应时在 Python 中中止 GET 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31998421/

相关文章:

python - 想要根据条件连接两个数据框的最后一行

python - zeromq 持久化模式

http - 在 http 处理程序中执行 Goroutine

asp.net - 如何将页面从 ASP.NET 发布到经典 ASP

php - 如何在 url php 中返回 $_GET 变量的名称

python - 您如何使用 Python 区分 Tumblr 中的原始帖子和转发?

python - 在 python 中构建不同的对

java - 读取Java中的错误响应主体

ruby - 如何使用修改后的 header 制作 HTTP GET?

Python从安全网站获取数据