Python相当于Perl的HTTP :: Async-> next_response

时间:2013-05-17 06:21:52

标签: python perl http asynchronous python-3.x

我正在寻找一种方法来做相当于Perl的HTTP :: Async模块的next_response方法

HTTP :: Async模块不会产生任何后台线程,也不会使用任何回调。相反,每当任何人(在我的情况下,主线程)调用对象上的next_response时,操作系统到目前为止接收的所有数据都被读取(阻塞,但是瞬时,因为它只处理已经接收的数据)。如果这是响应的结束,则next_response返回HTTP :: Response对象,否则返回undef。

此模块的用法类似于(伪代码):

request = HTTP::Async(url)
do:
    response = request->next_response()
    if not response:
        sleep 5 # or process events or whatever
while not response

# Do things with response

据我所知,Python的urllib或http.client不支持这种风格。至于为什么我想用这种风格来做:

  • 这是一个嵌入式Python环境,我不能生成线程,也不能生成任何Python。
  • 我只限于一个实际上是嵌入应用程序线程的线程。这意味着我也不能有任何延迟回调 - 应用程序决定何时运行我的Python代码。我所能做的就是请求嵌入式应用程序每50毫秒调用一次我选择的回调,比如说。

有没有办法在Python中执行此操作?

作为参考,这是我现在拥有的Perl代码的一个例子,我正在寻找移植到Python的代码:

httpAsync = HTTP::Async->new()

sub httpRequestAsync {
    my ($url, $callback) = @_; # $callback will be called with the response text

    $httpAsync->add(new HTTP::Request(GET => $url));

    # create_timer causes the embedding application to call the supplied callback every 50ms
    application::create_timer(50, sub {
        my $timer_result = application::keep_timer;
        my $response = $httpAsync->next_response;
        if ($response) {
            my $responseText = $response->decoded_content;
            if ($responseText) {
                $callback->($responseText);
            }
            $timer_result = application::remove_timer;
        }

        # Returning application::keep_timer will preserve the timer to be called again.
        # Returning application::remove_timer will remove the timer.
        return $timer_result;
    });
}

httpRequestAsync('http://www.example.com/', sub {
    my $responseText = $_[0];
    application::display($responseText);
});

编辑:鉴于这是针对嵌入式Python实例,我将采取我可以获得的所有替代方案(标准库的一部分或其他方式),因为我必须评估所有这些以确保它们可以运行在我特别的限制下。

1 个答案:

答案 0 :(得分:0)

注意:如果您只想在收到要接收的数据时检索数据,只需向handle_receive添加一个标志,然后将其添加到handle_receive内的睡眠块中,从而为您提供数据只有当你打电话给你的功能时。

#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
import asyncore, errno
from socket import AF_INET, SOCK_STREAM
from time import sleep

class sender():
    def __init__(self, sock_send):
        self.s = sock_send
        self.bufferpos = 0
        self.buffer = {}
        self.alive = 1

    def send(self, what):
        self.buffer[len(self.buffer)] = what

    def writable(self):
        return (len(self.buffer) > self.bufferpos)

    def run(self):
        while self.alive:
            if self.writable():
                logout = str([self.buffer[self.bufferpos]])
                self.s(self.buffer[self.bufferpos])
                self.bufferpos += 1
            sleep(0.01)

class SOCK(asyncore.dispatcher):
    def __init__(self, _s=None, config=None):
        self.conf = config
        Thread.__init__(self)

        self._s = _s

        self.inbuffer = ''
        #self.buffer = ''
        self.lockedbuffer = False
        self.is_writable = False

        self.autounlockAccounts = {}

        if _s:
            asyncore.dispatcher.__init__(self, _s)
            self.sender = sender(self.send)

        else:
            asyncore.dispatcher.__init__(self)
            self.create_socket(AF_INET, SOCK_STREAM)
            #if self.allow_reuse_address:
            #   self.set_resue_addr()

            self.bind((self.conf['SERVER'], self.conf['PORT']))
            self.listen(5)

            self.sender = None

        self.start()

    def parse(self):
        self.lockedbuffer = True

        ## Parse here
        print self.inbuffer

        self.inbuffer = ''
        self.lockedbuffer = False

    def readable(self):
        return True
    def handle_connect(self):
        pass
    def handle_accept(self):
        (conn_sock, client_address) = self.accept()
        if self.verify_request(conn_sock, client_address):
            self.process_request(conn_sock, client_address)
    def process_request(self, sock, addr):
        x = SOCK(sock, config={'PARSER' : self.conf['PARSER'], 'ADDR' : addr[0], 'NAME' : 'CORE_SUB_SOCK_('+str(addr[0]) + ')'})
    def verify_request(self, conn_sock, client_address):
        return True
    def handle_close(self):
        self.close()
            if self.sender:
                self.sender.alive = False
    def handle_read(self):
        data = self.recv(8192)
        while self.lockedbuffer:
            sleep(0.01)
        self.inbuffer += data
    def writable(self):
        return True
    def handle_write(self):
        pass

    def run(self):
            if not self._s:
            asyncore.loop()

imap = SOCK(config={'SERVER' : '', 'PORT' : 6668})
imap.run()

while 1
    sleep(1)

有什么想法吗? 当有数据要接收时,Asyncore套接字总是附加到inbuffer。

你可以根据需要修改它,我只是粘贴了另一个碰巧是Threaded的项目中的一段代码:)

上次尝试:

class EchoHandler(asyncore.dispatcher_with_send):

    def handle_read(self):
        data = self.recv(8192)
        if data:
            self.send(data)