【问题标题】:Using Python “requests” with existing socket connection将 Python “请求”与现有套接字连接一起使用
【发布时间】:2013-01-17 20:57:14
【问题描述】:

Python“请求”库目前风靡一时,因为它为发出 HTTP 请求提供了漂亮的接口——但在它之下似乎有许多间接层——会话、HTTP 适配器,最后是urllib3.

如果我已经持有一个打开的套接字,并且想使用“请求”向该套接字发送 HTTP 响应并接收回复,那么在这个抽象堆栈中的哪个位置进行干预?

如果没有某种干预(或定制?),堆栈将尝试为我创建一个新的 TCP/IP 套接字,但在我的特定应用程序中,我的代码在代表我建立连接之前不会被调用,因此,如果我希望能够使用 Requests 的功能,我需要说服 Requests 使用现有的套接字。

请求库:

http://pypi.python.org/pypi/requests

https://github.com/kennethreitz/requests

【问题讨论】:

    标签: python http sockets python-requests


    【解决方案1】:

    以下代码需要来自git的请求(尤其是requests.packages.urllib3.poolmanager.PoolManager._new_pool()

    我使用ncat -v -l 127.0.0.1 8000对其进行了测试

    问题在于,连接不是由 urllib3 而是由标准库中的 httplib 打开的。

    import socket
    import requests
    from requests.adapters import HTTPAdapter
    from requests.packages.urllib3 import PoolManager, HTTPConnectionPool
    
    try:
        from http.client import HTTPConnection
    except ImportError:
        from httplib import HTTPConnection
    
    
    class MyAdapter(HTTPAdapter):
        def init_poolmanager(self, connections, maxsize):
            self.poolmanager = MyPoolManager(num_pools=connections,
                                             maxsize=maxsize)
    
    
    class MyPoolManager(PoolManager):
        def _new_pool(self, scheme, host, port):
            # Important!
            if scheme == 'http' and host == my_host and port == my_port:
                return MyHTTPConnectionPool(host, port, **self.connection_pool_kw)
            return super(PoolManager, self)._new_pool(self, scheme, host, port)
    
    
    class MyHTTPConnectionPool(HTTPConnectionPool):
        def _new_conn(self):
            self.num_connections += 1
            return MyHTTPConnection(host=self.host,
                                port=self.port,
                                strict=self.strict)
    
    
    class MyHTTPConnection(HTTPConnection):
        def connect(self):
            """Connect to the host and port specified in __init__."""
            # Original
            # self.sock = socket.create_connection((self.host, self.port),
            #                                    self.timeout, self.source_address)
            # Important!
            self.sock = my_socket
            if self._tunnel_host:
                self._tunnel()
    
    
    if __name__ == '__main__':
        import time
    
        my_host = '127.0.0.1'
        my_port = 8000
    
        my_socket = socket.create_connection((my_host, my_port))
        time.sleep(4)
        s = requests.Session()
        s.mount('http://', MyAdapter())
        s.get('http://127.0.0.1:8000/foo')
    

    编辑:

    或者直接对连接池进行monkeypatching:

    class MyHTTPConnection(HTTPConnection):
        def connect(self):
            self.sock = my_socket
            if self._tunnel_host:
                self._tunnel()
    
    requests.packages.urllib3.connectionpool.HTTPConnection = MyHTTPConnection
    
    if __name__ == '__main__':
        my_host = '127.0.0.1'
        my_port = 8000
    
        my_socket = socket.create_connection((my_host, my_port))
        requests.get('http://127.0.0.1:8000/foo')
    

    【讨论】:

    • 这个猴子补丁对我不起作用。我不确定它是否从未起作用,或者请求在过去四年中是否发生了变化,但我的课程没有被使用(至少,它的 __init__connect 方法从未被调用过)。我正在使用 python 3.5 并请求 2.18.1。
    【解决方案2】:

    直接去urllib3库;它在urllib3.connectionpool module 中拥有一个连接池。

    您可以更换池或通过破解poolmanager module 来调整它。

    【讨论】:

      猜你喜欢
      • 2012-07-28
      • 2011-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 2022-01-26
      • 1970-01-01
      • 2017-02-10
      相关资源
      最近更新 更多