Tôi đang cố gắng thực hiện this Matasano crypto challenge liên quan đến việc thực hiện tấn công theo thời gian đối với máy chủ có chức năng so sánh chuỗi bị chậm giả tạo. Nó nói để sử dụng "khung web của bạn lựa chọn", nhưng tôi không cảm thấy như cài đặt một khuôn khổ web, vì vậy tôi quyết định sử dụng các HTTPServer class được xây dựng vào mô-đun http.server
.Ngoại lệ bí ẩn khi thực hiện nhiều yêu cầu đồng thời từ urllib.request đến HTTPServer
Tôi đã đưa ra một cái gì đó đã làm việc, nhưng nó đã rất chậm, vì vậy tôi đã cố gắng tăng tốc nó bằng cách sử dụng hồ bơi chủ đề (kém tài liệu) được xây dựng thành multiprocessing.dummy
. Nó nhanh hơn nhiều, nhưng tôi nhận thấy điều gì đó kỳ lạ: nếu tôi thực hiện 8 yêu cầu ít hơn đồng thời, nó hoạt động tốt. Nếu tôi có nhiều hơn thế, nó hoạt động trong một thời gian và cho tôi lỗi ở những thời điểm dường như ngẫu nhiên. Các lỗi dường như không nhất quán và không phải lúc nào cũng giống nhau, nhưng chúng thường có Connection refused, invalid argument
, OSError: [Errno 22] Invalid argument
, urllib.error.URLError: <urlopen error [Errno 22] Invalid argument>
, BrokenPipeError: [Errno 32] Broken pipe
hoặc urllib.error.URLError: <urlopen error [Errno 61] Connection refused>
trong đó.
Có giới hạn nào về số lượng kết nối mà máy chủ có thể xử lý không? Tôi không nghĩ rằng số lượng luồng cho mỗi bài viết là vấn đề, bởi vì tôi đã viết một hàm đơn giản làm so sánh chuỗi bị chậm lại mà không cần chạy máy chủ web và gọi nó với 500 chuỗi đồng thời và nó hoạt động tốt. Tôi không nghĩ rằng chỉ đơn giản là yêu cầu từ nhiều chủ đề đó là vấn đề, bởi vì tôi đã tạo ra các trình thu thập thông tin sử dụng hơn 100 luồng (tất cả yêu cầu đồng thời cho cùng một trang web) và chúng hoạt động tốt. Có vẻ như HTTPServer không có nghĩa là lưu trữ tin cậy các trang web sản xuất có lượng lưu lượng truy cập lớn, nhưng tôi ngạc nhiên rằng điều này rất dễ gây ra sự cố.
Tôi đã cố gắng xóa nội dung khỏi mã của mình trông không liên quan đến vấn đề, như tôi thường làm khi chẩn đoán các lỗi bí ẩn như thế này, nhưng điều đó không hữu ích trong trường hợp này. Có vẻ như tôi đang xóa mã dường như không liên quan, số lượng kết nối mà máy chủ có thể xử lý dần dần tăng lên, nhưng không có nguyên nhân rõ ràng nào về các sự cố.
Có ai biết cách tăng số lượng yêu cầu tôi có thể thực hiện cùng một lúc hay ít nhất là tại sao điều này xảy ra?
Mã của tôi là phức tạp, nhưng tôi đã đưa ra chương trình này đơn giản mà chứng tỏ vấn đề:
#!/usr/bin/env python3
import os
import random
from http.server import BaseHTTPRequestHandler, HTTPServer
from multiprocessing.dummy import Pool as ThreadPool
from socketserver import ForkingMixIn, ThreadingMixIn
from threading import Thread
from time import sleep
from urllib.error import HTTPError
from urllib.request import urlopen
class FancyHTTPServer(ThreadingMixIn, HTTPServer):
pass
class MyRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
sleep(random.uniform(0, 2))
self.send_response(200)
self.end_headers()
self.wfile.write(b"foo")
def log_request(self, code=None, size=None):
pass
def request_is_ok(number):
try:
urlopen("http://localhost:31415/test" + str(number))
except HTTPError:
return False
else:
return True
server = FancyHTTPServer(("localhost", 31415), MyRequestHandler)
try:
Thread(target=server.serve_forever).start()
with ThreadPool(200) as pool:
for i in range(10):
numbers = [random.randint(0, 99999) for j in range(20000)]
for j, result in enumerate(pool.imap(request_is_ok, numbers)):
if j % 20 == 0:
print(i, j)
finally:
server.shutdown()
server.server_close()
print("done testing server")
Đối với một số lý do, chương trình trên hoạt động tốt trừ khi nó có hơn 100 chủ đề hoặc lâu hơn, nhưng tôi mã thực sự cho thử thách chỉ có thể xử lý 8 luồng. Nếu tôi chạy nó với 9, tôi thường nhận được lỗi kết nối, và với 10, tôi luôn luôn nhận được lỗi kết nối. Tôi đã thử sử dụng concurrent.futures.ThreadPoolExecutor
, concurrent.futures.ProcessPoolExecutor
và multiprocessing.pool
thay vì multiprocessing.dummy.pool
và không ai trong số đó có vẻ hữu ích. Tôi đã thử sử dụng đối tượng đơn giản là HTTPServer
(không có ThreadingMixIn
) và điều đó khiến mọi thứ chạy rất chậm và không khắc phục được sự cố. Tôi đã thử sử dụng ForkingMixIn
và điều đó cũng không khắc phục được.
Tôi phải làm gì với điều này? Tôi đang chạy Python 3.5.1 vào cuối năm 2013 MacBook Pro chạy OS X 10.11.3.
EDIT: tôi đã cố gắng thêm vài thứ, bao gồm chạy các máy chủ trong một quá trình thay vì một chủ đề, như một đơn giản HTTPServer
, với ForkingMixIn
, và với sự ThreadingMixIn
. Không ai giúp.
EDIT: Vấn đề này lạ hơn tôi nghĩ.Tôi đã thử tạo một kịch bản với máy chủ và một tập lệnh khác với nhiều luồng tạo yêu cầu và chạy chúng trong các tab khác nhau trong thiết bị đầu cuối của tôi. Quá trình với máy chủ chạy tốt, nhưng yêu cầu thực hiện đã bị lỗi. Các trường hợp ngoại lệ là kết hợp của ConnectionResetError: [Errno 54] Connection reset by peer
, urllib.error.URLError: <urlopen error [Errno 54] Connection reset by peer>
, OSError: [Errno 41] Protocol wrong type for socket
, urllib.error.URLError: <urlopen error [Errno 41] Protocol wrong type for socket>
, urllib.error.URLError: <urlopen error [Errno 22] Invalid argument>
.
Tôi đã thử với một máy chủ giả như trên và nếu tôi giới hạn số lượng yêu cầu đồng thời xuống 5 hoặc ít hơn, nó hoạt động tốt, nhưng với 6 yêu cầu, quy trình khách hàng bị lỗi. Đã có một số lỗi từ máy chủ, nhưng nó vẫn tiếp diễn. Khách hàng đã gặp bất kể tôi có đang sử dụng các luồng hoặc các quy trình để thực hiện các yêu cầu hay không. Sau đó tôi đã thử đặt chức năng bị chậm lại trong máy chủ và nó có thể xử lý 60 yêu cầu đồng thời, nhưng nó bị lỗi với 70. Điều này có vẻ như nó có thể mâu thuẫn với bằng chứng rằng vấn đề là với máy chủ.
EDIT: Tôi đã thử hầu hết những điều tôi mô tả bằng cách sử dụng requests
thay vì urllib.request
và gặp sự cố tương tự.
EDIT: Tôi hiện đang chạy OS X 10.11.4 và chạy vào cùng một vấn đề.
Bạn có đảm bảo bạn đang đóng các kết nối khách hàng không được sử dụng của mình không? –
@Cory Shay, tôi đã thử làm 'x = urlopen (bất kỳ)' sau đó 'x.close()', và điều đó dường như không giúp ích gì. –
Tôi phải thừa nhận rằng lý do mà tôi đã nêu không nhất thiết là lý do tại sao vấn đề này xảy ra. Có khả năng có thể là những người khác. Nhưng một số câu hỏi để hỏi có thể giúp điều tra điều này là "điều gì xảy ra nếu bạn phát hành' ulimit -r $ ((32 * 1024)) '?" và "đầu ra từ' netstat -anp | grep SERVERPROCESSNAME' là gì? " –