loadlj / blog

19 stars 6 forks source link

HTTPClient分析 #5

Open loadlj opened 8 years ago

loadlj commented 8 years ago

HTTPClient

Blocking and non-blocking HTTP client implementations using pycurl Blocking client指的是HTTPClient,non-blocking HTTP client指的是AsyncHTTPClient

HTTPClient

函数说明

__init__

调用_curl_create初始化self._curl。

def _curl_create(max_simultaneous_connections=None):
    curl = pycurl.Curl()
    if logging.getLogger().isEnabledFor(logging.DEBUG):
        curl.setopt(pycurl.VERBOSE, 1)
        curl.setopt(pycurl.DEBUGFUNCTION, _curl_debug)
    curl.setopt(pycurl.MAXCONNECTS, max_simultaneous_connections or 5)
    return curl

fetch

将参数中的requets和kwargs封装成一个HTTPRequest对象,调用_curl_setup_request设置self.curl各种参数。将self.curl返回的buffer和反回的url以及请求信息封装成一个HTTPResponse对象.

AsyncHTTPClient

函数说明

__new__

这里初始化使用的是new而不是init, 可参照difference。还有_ASYNC_CLIENTS需要注意,源代码中的解释是There is one client per IOLoop since they share curl instances

_ASYNC_CLIENTS = weakref.WeakKeyDictionary()
cls._ASYNC_CLIENTS[io_loop] = instance

这段代码确保当AsyncHTTPClient被销毁的时候,ioloop也随之被销毁, 且每个AsyncHTTPClient只对应一个IOLoop。

fetch

接受一个httprequest和一个callback, 将request封装成一个HTTPRequest,将request和相应的callback存到self.request中。调用self._add_perform_callback()

_handle_socket

libcurl回调更改文件描述符状态。声明一个event_map, 将libculr文件描述符封装成ioloop文件描素福状态,包括pycurl.POLL_INpycurl.POLL_OUT等。 将封装好的事件传入到ioloop中,设置handlerioloop_event

_handle_events

ioloop回调更改文件描述符状态, 调用socket_action接口,调用self._finish_pending_requests

_finish_pending_requests

调用info_read取出curl返回的信息。

num_q, ok_list, err_list = self._multi.info_read

调用self._finish处理curl, 调用_process_queue

_process_queue

self._free_list中的curl对象取出来,取出self._requests中的requestcallback构造curl对象,将其加入到self._multi中。

_finish

读取curl的info,封装一个HTTPResponse对象,调用info中的callback

通过代码分析流程图

from tornado import ioloop, httpclient

def handle_request(response):
    if response.error:
        print "Error:", response.error
    else:
        print response.body
    ioloop.IOLoop.instance().stop()

http_client = httpclient.AsyncHTTPClient2()
http_client.fetch("http://www.baidu.com", handle_request)
ioloop.IOLoop.instance().start()

流程图