[英]Proxy server made with sockets (python) receiving and sending in incorrect order
我試圖制作一個簡單的代理服務器,可用於將任何請求消息中繼到某個目標主機,然后接收響應並將其中繼回原始發件人(客戶端)。 我的實現導致第一個請求消息的響應在服務器中停滯,並且它僅作為第二個請求消息的響應被接收。 這會導致一些錯誤。 我試圖將它用作 http 代理,在 localhost 上運行一個簡單的 http 服務器,代理也在 localhost 上,並使用我的瀏覽器向代理發送 GET 消息。
下面是代碼
class Proxy:
def __init__(self,mhost,mport,dhost,dport):
self.mhost = mhost
self.mport = mport
self.dhost = dhost
self.dport = dport
#self.middle_man = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#self.middle_man.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.colorAndFormat = ColorAndFormat() # Just for coloring the output text
def start_listener(self):
colorAndFormat = ColorAndFormat()
middle_man_recv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
middle_man_recv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
middle_man_recv.bind((self.mhost, self.mport))
middle_man_recv.listen()
print(colorAndFormat.Blue2("Listening on " + self.mhost + ':' + str(self.mport) + ' ...\n---------------------------------'))
middle_man_forw = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
middle_man_forw.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#middle_man_forw.connect_ex((self.dhost, self.dport))
while True:
#try:
# Receive data
client_socket,client_addr = middle_man_recv.accept()
data = client_socket.recv(1024)
print(colorAndFormat.Blue2("Data received from client " + client_addr[0] + ':' + str(client_addr[1])))
print(colorAndFormat.Blue2(data.decode()))
# Forward data to dhost:dport
middle_man_forw.connect_ex((self.dhost, self.dport))
middle_man_forw.sendall(data)
print(colorAndFormat.Beige("Data forwarded to " + self.dhost + ':' + str(self.dport)))
# Receive data from dhost:dport
data = middle_man_forw.recv(1024)
print(colorAndFormat.Beige("Data received from " + self.dhost + ':' + str(self.dport)))
print(colorAndFormat.Beige(data.decode()))
# Forward data to client
client_socket.sendall(data)
print(colorAndFormat.Blue2("Data forwarded to client"))
print('---------------------------------')
client_socket.close()
#except
下面是發送 GET 請求的輸出。 (index.html 存在)
Listening on 127.0.0.1:4444 ...
---------------------------------
Data received from client 127.0.0.1:60032
GET /index.html HTTP/1.1
Host: 127.0.0.1:4444
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Data forwarded to 127.0.0.1:8888
Data received from 127.0.0.1:8888
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.8.3
Date: Tue, 17 Nov 2020 20:13:53 GMT
Content-type: text/html
Content-Length: 116
Last-Modified: Tue, 17 Nov 2020 19:49:32 GMT
Data forwarded to client
---------------------------------
Data received from client 127.0.0.1:60036
GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:4444
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: image/webp,*/*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Data forwarded to 127.0.0.1:8888
Data received from 127.0.0.1:8888
<html>
<head><title>This worksss!!</title></head>
<body>
If you're seeing this, the Proxy works!!
</body>
</html>
Data forwarded to client
---------------------------------
Data received from client 127.0.0.1:60038
GET /index.html HTTP/1.1
Host: 127.0.0.1:4444
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Traceback (most recent call last):
File "exposer.py", line 176, in <module>
exposer.start_listener()
File "exposer.py", line 40, in start_listener
middle_man_forw.sendall(data)
BrokenPipeError: [Errno 32] Broken pipe
這個實現有錯嗎?
data = middle_man_forw.recv(1024)
您希望data
包含服務器的完整響應。 這種期望是錯誤的。 首先,它可能超過您嘗試讀取的 1024 個字節。 然后,即使總數據少於 1024 字節, recv
也可能只返回一部分數據。
這樣做的原因是 TCP 不是消息協議,而只是字節流。 但是您希望recv
完整的消息,並假設 HTTP 響應是單個消息。
關於如何處理這個問題,基本上有兩種方法:您可以繼續使用您首先期望 HTTP 請求、轉發它、期望 HTTP 響應並轉發它的方法。 但是你需要確保你真正閱讀了完整的請求和響應,即你必須理解並正確實現 HTTP 協議。
另一種方法是簡單地將所有內容從客戶端轉發到服務器,並並行地將所有內容從服務器轉發到客戶端。 在這種情況下,您實際上並不關心講的是什么協議,而只是盲目地轉發所有內容。 這種方法可以通過線程(每個方向一個線程)、選擇或類似方式實現。 例如,對於基於選擇的方法,請參閱不到 100 行代碼的 Python 代理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.