簡體   English   中英

用套接字(python)制作的代理服務器以錯誤的順序接收和發送

[英]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.

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