【问题标题】:proxy server not sending all data python代理服务器不发送所有数据python
【发布时间】:2017-04-15 12:07:39
【问题描述】:

我在 python 中创建了一个 HTTP 代理,但我遇到了麻烦,因为我的代理只会接受网络服务器的响应,并且会完全忽略浏览器的下一个请求,并且数据传输会停止。代码如下:

import socket

s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

bhost = '192.168.1.115'
port = 8080
s.bind((bhost, port))
s.listen(5)

def server(sock, data, host):
    p = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    p.connect((host, 80))
    p.send(data)
    rdata = p.recv(1024)
    print(rdata)
    sock.send(rdata)


    while True:
        sock, addr = s.accept()
        data = sock.recv(1024)
        host = data.splitlines()[1][6:]
        server(sock, data, host)`

对不起,这只是一个试用版的代码,我们将不胜感激,因为我只有 14 岁,还有很多东西要学:-)

【问题讨论】:

  • 这种格式很奇怪,因为您在server() 中接受连接,然后再次调用server()。这是故意的吗?

标签: python sockets http proxy server


【解决方案1】:

不幸的是,我并没有真正了解您的代码应该如何工作,所以我在这里提出了我对简单 HTTP 代理应该是什么样子的想法。 那么一个基本的代理服务器应该做什么:

  1. 接受来自客户端的连接并接收 HTTP 请求。
  2. 解析请求并提取其目的地。
  3. 转发请求和响应。
  4. (可选)支持Connection: keep-alive

让我们一步一步写一些非常简化的代码。

代理如何接受客户端。应该创建一个套接字并将其移至被动模式:

import socket, select
sock = socket.socket()
sock.bind((your_ip, port))
sock.listen()
while True:
   client_sock = sock.accept()
   do_stuff(client_sock)

一旦建立 TCP 连接,是时候接收请求了。假设我们会得到这样的东西:

GET /?a=1&b=2 HTTP/1.1 
Host: localhost    
User-Agent: my browser details
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8    
Accept-Language: en-gb,en;q=0.5    
Accept-Encoding: gzip, deflate    
Connection: keep-alive

在 TCP 中,不保留消息边界,因此我们应该等到至少获得前两行(对于 GET 请求)才能知道以后要做什么:

def do_stuff(sock):
    data = receive_two_lines(sock)
    remote_host = parse_request(data)

获得远程主机名后,就可以转发请求和响应了:

def do_stuff(client_sock):
    data = receive_two_lines(client_sock)
    remote_host = parse_request(data)
    remote_ip = socket.getaddrinfo(remote_host)  # see the docs for exact use

    webserver = socket.socket()
    webserver.connect((remote_ip, 80))

    webserver.sendall(data)
    while it_makes_sense():
        client_ready = select.select([client_sock], [], [])[0]
        web_ready = select.select([webserver], [], [])[0]

        if client_ready:
            webserver.sendall(client_sock.recv(1024))
        if web_ready:
            client_sock.sendall(webserver.recv(1024))

请注意select - 这是我们知道远程对等方是否向我们发送数据的方式。我还没有运行和测试这段代码,还有一些事情要做:

  1. 很有可能,您将在单个client_sock.recv(1024) 调用中收到多个GET 请求,因为TCP 中没有保留消息边界。每次收到数据时,可能会查看额外的 get 请求。
  2. 对于 POST、HEAD、PUT、DELETE 和其他类型的请求,请求可能不同。相应地解析它们。
  3. 浏览器和服务器通常通过在标头中设置Connection: keep-alive 选项来使用一个TCP 连接,但它们也可能决定放弃它。准备好检测远程对等方关闭的断开连接和套接字(为简单起见,在代码中称为while it_makes_sense())。
  4. bindlistenacceptrecvsendsendallgetaddrinfoselect - 所有这些函数都可以抛出异常。最好抓住它们并采取相应的行动。
  5. 代码当前一次为一个客户端提供服务。

【讨论】:

  • 感谢 Vovanrock2002 这真的帮助了我 :-)
  • 我正在计划我的代码;当它运行时接受连接并接收 HTTP 请求,然后解析它以找到主机,然后将其提供给服务器功能,该功能将连接到主机并从浏览器发送 HTTP 请求并接收响应并将其发送到浏览器,并且所有这些都只是一个不断循环的循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多