簡體   English   中英

使用現有套接字連接的Python“請求”

[英]Using Python “requests” with existing socket connection

Python“請求”庫目前風靡一時,因為它提供了用於發出HTTP請求的漂亮界面 - 但在它下面似乎有很多層間接 - 會話,HTTP適配器,最后是urllib3的機制。

如果我已經擁有一個打開的套接字,並希望使用“請求”在該套接字下發送HTTP響應並收到回復,那么在這個抽象堆棧中哪里是干預的正確位置?

如果沒有某種干預(或自定義?),堆棧將嘗試為我創建一個新的TCP / IP套接字,但在我的特定應用程序中,我的代碼在代表我已建立連接之前不會被調用,所以我會如果我想能夠使用請求的功能,需要說服請求在現有套接字上進行通話。

請求庫:

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

https://github.com/kennethreitz/requests

以下代碼需要來自git的requests.packages.urllib3.poolmanager.PoolManager._new_pool()尤其是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')

直接進入urllib3庫; 它在urllib3.connectionpool模塊中擁有一個連接池。

您可以替換池或通過黑客池poolmanager模塊來調整它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM