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