繁体   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