2015-01-30 15 views
8

I asked a question o tym, jak zdławić przesyłanie Pythona, który wysłał mnie do this answer, gdzie zostałem poinformowany o małej bibliotece pomocniczej o nazwie socket-throttle. To wszystko w porządku i dandy dla zwykłego HTTP i prawdopodobnie również dla większości zwykłych zastosowań gniazda. Jednak staram się udusić połączenia SSL i próbuje połączyć socket-throttle z biblioteką Zdjęcie SSL (stosowane w sposób dorozumiany przez requests) powoduje wyjątek głęboko w trzewiach biblioteki:Przepustowość przepustowości połączenia SSL

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' 

Dobrze, że to downer. Jak można się przekonać, pakiet ssl próbuje użyć jednego z prywatnych pól gniazda, _sock zamiast samego socket. (Czy nie chodzi o prywatne pola, do których nie ma się dostępu z zewnątrz?) Jeśli spróbuję wstrzyknąć się w to pole na moim obiekcie ThrottledSocket, natknę się na ten 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 

Co teraz? Czy jest jeszcze gdzieś w tym miejscu, gdzie mogę ograniczyć szybkość komunikacji Pythona? Czy jest to czystszy sposób na to, niż zastąpienie implementacji gniazda? Co zresztą okazuje się być dyskusyjne, ponieważ pakiet ssl próbuje go ominąć.

+0

Powodem 'ssl' jest zakorzenienie w prywatnych' wokół pól socket' jest, pod spodem C Biblioteka dla TLS, 'openssl', bardzo chce rozmawiać bezpośrednio do Ja- deskryptor gniazda poziomu. Zamiast tego można zmienić 'socket-throttle' tak, aby powtarzał' ssl.wrap_socket' * zamiast * 'socket.socket' - potrzebujesz owijki przepustnicy * poza * opakowaniem TLS. Nie mam zamiaru zamieszczać tego jako odpowiedzi, ponieważ nie wiem, czy to zadziała, a nawet jeśli tak się stanie, będzie to prawdopodobnie dużo majsterkowania. Powodzenia? – zwol

+0

Biblioteka ssl nie gniewa się w prywatnych jajach obiektu 'socket.socket'. 'ssl.wrap_socket' zwraca nowy obiekt, który przechowuje oryginalną instancję' socket.socket' na nim jako '_sock'. Ma wszelkie prawo do korzystania z własnego prywatnego atrybutu. Następnym razem przeczytaj źródło przed wydaniem takich oświadczeń o innych bibliotekach. Ponadto, jako punkt porządku, wyjątek pochodzi z 'ssl' /' socket-throttle', ale powoduje przepełnienie żądań. Żądania nie są za to odpowiedzialne. –

Odpowiedz

1

Wygląda na to, że próbujesz ograniczyć liczbę żądań HTTP. W takim przypadku możesz zamiast tego spróbować RequestsThrottler. Python requests jest o wiele ładniejszy niż httplib.

+0

Używam biblioteki żądań (która z kolei używa httplib). Ten 'RequestsThrottler' wydaje się obiecujący, ale muszę go przetestować, aby się upewnić, zanim zaakceptuję twoją odpowiedź. :) Nie miałem problemów z ograniczaniem połączeń HTTP, ale połączenia HTTPS są tam, gdzie mam problem. – Alex

+0

Albo nie rozumiem, jak działa RequestsThrottler, albo ma wpływ tylko na pobieranie, nie na wysyłanie. Muszę zmniejszyć przepustowość, jak mówi pierwsza linia w moim pytaniu. Czy jest szansa, że ​​dostarczysz mi działającą próbkę, jeśli masz ją wcześniej? – Alex

4

W zależności od wymagań, możesz i może rozwiązać ten konkretny problem na poziomie systemu operacyjnego, a nie na poziomie aplikacji.

Zbliżanie się do tego na poziomie systemu operacyjnego ma dwie zalety. Po pierwsze, nie ma znaczenia, w jaki sposób wykorzystywane są gniazda (HTTP lub HTTPS lub IRC lub niektóre ping pakietów śmierci - to nie ma znaczenia). Po drugie, im bardziej rozłączasz różne komponenty systemu, tym łatwiej jest wprowadzać zmiany i rozwiązywać problemy.

Istnieją narzędzia (przynajmniej dla systemów zgodnych z POSIX) do ograniczania przepustowości interfejsów sieciowych i/lub procesów. Czasami warto spojrzeć na nich, na przykład:

  • trickle (dla kształtowania ruchu procesów)
  • wondershaper (do kształtowania ruchu całych interfejsów sieciowych, mam faktycznie używane to od wewnątrz nowoczesnego Ubuntu i działa perfekcyjnie)

te dyskusje mogą być istotne dla Ciebie:

+0

Miałem nadzieję udostępnić użytkownikowi konfigurowalne ustawienie przesyłania (i prawdopodobnie pobierania) w samym programie. Wygląda na to, że rozwiązanie będzie wyglądało tak, jakby rozwiązało mój problem, ale także usuwa kontrolę nad sytuacją z mojego programu do zewnętrznego podmiotu ... nadal, naprawdę zaczynam tracić nadzieję na tę sytuację. Albo Python po prostu * nie może zrobić * o co pytam, albo jest tak skomplikowany lub ezoteryczny, że nikt na Stack Overflow nie wie jak. Szczerze mówiąc, myślałem, że to stosunkowo powszechny scenariusz, ale zaczynam myśleć, że myliłem się w tym założeniu. – Alex

+0

Przejęcie kontroli nad ruchem sieciowym z pewnością * jest * możliwe, ale jest znacznie mniej trywialne, niż większość ludzi myśli. Stos TCP/IP jest niezwykle złożony i dobrze skonstruowany, zawierający wiele specjalnych algorytmów. Twój system operacyjny bardzo dobrze ukrywa przed Tobą tę złożoność. Możesz osiągnąć to, czego chcesz, po prostu nie w krótkim projekcie. Może to sprawi, że wrócisz do domu: jeśli strużka działa dla ciebie, możesz wysłać ją razem z aplikacją i umieścić wszystko w "opakowaniu", podczas gdy opakowanie konfiguruje tak samo jak twoją aplikację. –

+0

Przy okazji, możesz chcieć przekazać te odpowiedzi, które zapewniły ci pewien wgląd, nawet jeśli nie było to idealne rozwiązanie, które masz nadzieję uzyskać. ;) –

Powiązane problemy