2015-01-30 11 views
8

Ich asked a question über wie ein Python-Upload, die mich an this answer, wo ich von einer kleinen Helfer-Bibliothek namens socket-throttle genannt wurde geschickt wurde, zu drosseln. Das ist alles gut und schön für reguläres HTTP und wahrscheinlich auch für die meisten einfachen Anwendungen des Sockets. Aber ich versuche, eine SSL-Verbindung zu drosseln, und versuchen socket-throttle mit dem Bestand SSL-Bibliothek zu kombinieren (verwendet implizit durch requests) verursacht eine Ausnahme tief in den Eingeweiden der Bibliothek:Throttling Bandbreite einer SSL-Verbindung

File "***.py", line 590, in request 
    r = self.session.get(url, headers=extra_headers) 
    File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 394, in get 
    return self.request('GET', url, **kwargs) 
    File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 382, in request 
    resp = self.send(prep, **send_kwargs) 
    File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 485, in send 
    r = adapter.send(request, **kwargs) 
    File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 324, in send 
    timeout=timeout 
    File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py", line 478, in urlopen 
    body=body, headers=headers) 
    File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py", line 285, in _make_request 
    conn.request(method, url, **httplib_request_kw) 
    File "/usr/lib/python2.7/httplib.py", line 973, in request 
    self._send_request(method, url, body, headers) 
    File "/usr/lib/python2.7/httplib.py", line 1007, in _send_request 
    self.endheaders(body) 
    File "/usr/lib/python2.7/httplib.py", line 969, in endheaders 
    self._send_output(message_body) 
    File "/usr/lib/python2.7/httplib.py", line 829, in _send_output 
    self.send(msg) 
    File "/usr/lib/python2.7/httplib.py", line 791, in send 
    self.connect() 
    File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connection.py", line 95, in connect 
    ssl_version=resolved_ssl_version) 
    File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util.py", line 643, in ssl_wrap_socket 
    ssl_version=ssl_version) 
    File "/usr/lib/python2.7/ssl.py", line 487, in wrap_socket 
    ciphers=ciphers) 
    File "/usr/lib/python2.7/ssl.py", line 211, in __init__ 
    socket.__init__(self, _sock=sock._sock) 
    File "***/socket_throttle.py", line 54, in __getattr__ 
    return getattr(self._wrappedsock, attr) 
AttributeError: '_socket.socket' object has no attribute '_sock' 

Nun, das ist ein Wermutstropfen. Wie Sie sehen können, versucht das ssl-Paket, eines der privaten Felder des Sockets zu verwenden, _sock statt der socket selbst. (Ist das nicht der Punkt, der privaten Felder, die Sie nicht glauben, sie von außen zugreifen Grr?). Wenn ich versuche, mich auf meinem ThrottledSocket Objekt in diesen Bereich zu injizieren, ich laufe in dieses Problem:

File "/home/alex/dev/jottalib/src/jottalib/JFS.py", line 590, in request 
    r = self.session.get(url, headers=extra_headers) 
    File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 394, in get 
    return self.request('GET', url, **kwargs) 
    File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 382, in request 
    resp = self.send(prep, **send_kwargs) 
    File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 485, in send 
    r = adapter.send(request, **kwargs) 
    File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 324, in send 
    timeout=timeout 
    File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py", line 478, in urlopen 
    body=body, headers=headers) 
    File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py", line 285, in _make_request 
    conn.request(method, url, **httplib_request_kw) 
    File "/usr/lib/python2.7/httplib.py", line 973, in request 
    self._send_request(method, url, body, headers) 
    File "/usr/lib/python2.7/httplib.py", line 1007, in _send_request 
    self.endheaders(body) 
    File "/usr/lib/python2.7/httplib.py", line 969, in endheaders 
    self._send_output(message_body) 
    File "/usr/lib/python2.7/httplib.py", line 829, in _send_output 
    self.send(msg) 
    File "/usr/lib/python2.7/httplib.py", line 791, in send 
    self.connect() 
    File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connection.py", line 95, in connect 
    ssl_version=resolved_ssl_version) 
    File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util.py", line 643, in ssl_wrap_socket 
    ssl_version=ssl_version) 
    File "/usr/lib/python2.7/ssl.py", line 487, in wrap_socket 
    ciphers=ciphers) 
    File "/usr/lib/python2.7/ssl.py", line 241, in __init__ 
    ciphers) 
TypeError: must be _socket.socket, not ThrottledSocket 

Was nun? Gibt es woanders wo ich die Python-Kommunikation begrenzen könnte? Oder gibt es einen saubereren Weg, als die Socket-Implementierung zu überschreiben? Was sich sowieso als problematisch erweist, da das Paket ssl nur versucht, es komplett zu umgehen.

+0

Der Grund 'ssl' ist Verwurzelung um in privaten' socket' Feldern, die zugrunde liegenden C-Bibliothek für TLS, 'openssl' will sehr viel direkt mit dem OS- sprechen Level Socket Deskriptor. Was stattdessen funktionieren könnte, ist das Ändern von "socket-throttle", so dass es "ssl.wrap_socket" * anstelle von "socket.socket" "monkeypatches" - Sie benötigen den Gaswrapper * außerhalb des TLS-Wrappers. Ich werde das nicht als Antwort posten, weil ich nicht weiß, ob es funktioniert, und selbst wenn es funktioniert, wird es wahrscheinlich eine Menge Bastelei sein. Viel Glück? – zwol

+0

Die ssl-Bibliothek muckt nicht in den privaten Eingeweiden eines 'socket.socket'-Objekts herum. 'ssl.wrap_socket' gibt ein neues Objekt zurück, das die ursprüngliche Instanz von' socket.socket' als '_sock' speichert. Es hat jedes Recht, sein eigenes privates Attribut zu verwenden. Beim nächsten Mal lesen Sie bitte die Quelle, bevor Sie solche Aussagen über andere Bibliotheken machen. Auch, als ein Punkt der Reihenfolge, kommt die Ausnahme von 'ssl' /' socket-drossel', aber Blasen durch Anfragen. Anfragen sind dafür nicht verantwortlich. –

Antwort

1

Es sieht so aus, als ob Sie versuchen, HTTP-Anfragen zu drosseln. Wenn das der Fall ist, können Sie stattdessen RequestsThrottler versuchen. Python requests ist viel schöner als httplib auch.

+0

Ich benutze tatsächlich die Anfragen Bibliothek (die wiederum httplib verwendet). Dieser 'RequestsThrottler' scheint vielversprechend zu sein, aber ich werde ihn testen müssen, bevor ich deine Antwort akzeptiere. :) Ich hatte keine Probleme mit der Drosselung von HTTP-Verbindungen, aber HTTPS-Verbindungen ist, wo ich Probleme hatte. – Alex

+0

Entweder ich verstehe nicht, wie RequestsThrottler funktioniert, oder es betrifft nur Downloads, nicht Uploads. Ich muss Uploads drosseln, wie die erste Zeile in meiner Frage sagt. Gibt es eine Chance, dass Sie mir ein funktionierendes Beispiel zur Verfügung stellen könnten, wenn Sie es vorher schon einmal benutzt haben? – Alex

4

Je nach Ihren Anforderungen können und sollten Sie dieses spezielle Problem auf Betriebssystemebene statt auf Anwendungsebene lösen.

Die Annäherung an das Betriebssystem hat zwei Vorteile. Erstens macht es keinen Unterschied, wie die verwendeten Sockets verwendet werden (HTTP oder HTTPS oder IRC oder einige Ping-of-Death-Pakete - es spielt keine Rolle). Zweitens, je mehr Sie die verschiedenen Komponenten Ihres Systems entkoppeln, desto einfacher ist es, danach Änderungen vorzunehmen und Probleme zu beheben.

Es gibt Tools (zumindest für POSIX-konforme Systeme) zur Drosselung der Bandbreite von Netzwerkschnittstellen und/oder Prozessen. Vielleicht haben Sie einen Blick auf diese, zum Beispiel haben wollen:

  • trickle (für den Verkehr von Prozessen Gestaltung)
  • wondershaper (für den Verkehr ganzer Netzwerk-Schnittstellen Gestaltung, ich habe dies aus tatsächlich verwenden in einem modernen Ubuntu , und es funktioniert völlig in Ordnung)

Diese Gespräche könnten für Sie relevant sein:

+0

Ich hatte gehofft, dem Benutzer eine konfigurierbare Upload (und möglicherweise Download) Einstellung im Programm selbst zu bieten. Die Trickle-Lösung sieht so aus, als würde sie mein Problem lösen, aber es entfernt auch die Kontrolle über die Situation von meinem Programm zu einer externen Entität ... trotzdem, ich fange langsam an, die Hoffnung auf diese Situation zu verlieren. Entweder kann Python einfach nicht * das, wonach ich frage, oder es ist einfach so kompliziert oder esoterisch, dass niemand auf Stack Overflow weiß, wie. Ehrlich gesagt dachte ich, dies wäre ein relativ häufiges Szenario, aber ich fange an zu denken, dass ich mich in dieser Annahme irrte. – Alex

+0

Es ist sicher möglich, die Kontrolle über den Netzwerkverkehr zu übernehmen, aber es ist viel weniger trivial als die meisten Leute denken. Der TCP/IP-Stack ist unglaublich komplex und ausgereift und enthält viele spezielle Algorithmen. Ihr Betriebssystem kann diese Komplexität sehr gut verbergen. Sie können erreichen, was Sie wollen, nur nicht in einem kurzen Projekt. Vielleicht macht es Ihnen etwas zu Hause: Wenn Trickle für Sie funktioniert, können Sie es zusammen mit Ihrer Anwendung versenden und alles in einen "Wrapper" legen, während der Wrapper sowohl Trickle als auch Ihre App konfiguriert. –

+0

Übrigens möchten Sie möglicherweise die Antworten aufwerten, die Ihnen einen Einblick verschafft haben, auch wenn es nicht die perfekte Lösung war, die Sie erhofften. ;) –