📜  在Python中创建代理Web服务器 1

📅  最后修改于: 2020-05-13 05:09:58             🧑  作者: Mango

与c相比,Python中的套接字编程非常用户友好。程序员不必担心有关套接字的详细信息。在Python中,用户有更多机会专注于应用程序层而不是网络层。在本教程中,我们将开发一个能够处理HTTP流量的简单多线程代理服务器。它将主要基于基本的套接字编程思想。如果您不确定基础知识,那么我建议您在阅读本教程之前先将它们刷一下。
这是代理服务器的简单实现。在接下来的教程中,我们将逐步将其开发成非常有用的服务器。

首先,我们将通过3个简单的步骤来完成该过程
1.创建一个传入套接字
我们在服务器类的__init__方法中创建一个套接字serverSocket。这将为传入的连接创建一个套接字。然后,我们绑定套接字,然后等待客户端连接。

def __init__(self, config):
    # 在Ctrl + C上关机
    signal.signal(signal.SIGINT, self.shutdown)
    # 创建一个TCP套接字
    self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 重新使用插座
    self.serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # 将套接字绑定到公共主机和端口
    self.serverSocket.bind((config['HOST_NAME'], config['BIND_PORT']))
    self.serverSocket.listen(10) # become a server socket
    self.__clients = {}

2.接受客户和流程
这是所有步骤中最简单但最重要的步骤。我们等待客户端的连接请求,一旦建立成功连接,我们就在一个单独的线程中分派该请求,使自己可用于下一个请求。这使我们可以同时处理多个请求,从而将服务器的性能提高了数倍。

while True:
    # 建立连接
    (clientSocket, client_address) = self.serverSocket.accept()
    d = threading.Thread(name=self._getClientName(client_address),
    target = self.proxy_thread, args=(clientSocket, client_address))
    d.setDaemon(True)
    d.start()

3.重定向流量
代理服务器的主要功能是充当源和目标之间的中介。在这里,我们从源中获取数据,然后将其传递给客户端。

  • 首先,我们从接收到的请求数据中提取URL。
    # 从浏览器获取请求
    request = conn.recv(config['MAX_REQUEST_LEN'])
    # 解析第一行
    first_line = request.split('\n')[0]
    # 获取网址
    url = first_line.split(' ')[1]
  • 然后,我们找到请求的目标地址。地址是(destination_ip_address,destination_port_no)的元组。我们将从该地址接收数据。
    http_pos = url.find("://") # find pos of ://
    if (http_pos==-1):
        temp = url
    else:
        temp = url[(http_pos+3):] # get the rest of url
    port_pos = temp.find(":") # find the port pos (if any)
    # 找到网络服务器的末端
    webserver_pos = temp.find("/")
    if webserver_pos == -1:
        webserver_pos = len(temp)
    webserver = ""
    port = -1
    if (port_pos==-1 or webserver_pos < port_pos):
        # 默认端口
        port = 80
        webserver = temp[:webserver_pos]
    else: # 特定端口
        port = int((temp[(port_pos+1):])[:webserver_pos-port_pos-1])
        webserver = temp[:port_pos]
  • 现在,我们建立了到目标服务器(或远程服务器)的新连接,然后将原始请求的副本发送到服务器。然后,服务器将进行响应。所有响应消息都使用RFC 822的通用消息格式。
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(config['CONNECTION_TIMEOUT'])
    s.connect((webserver, port))
    s.sendall(request)
  • 然后,我们将服务器的响应重定向到客户端。conn是与客户端的原始连接。该响应可能大于我们在一个调用中收到的MAX_REQUEST_LEN,因此,空响应表示响应结束。
    while 1:
        # 从Web服务器接收数据
        data = s.recv(config['MAX_REQUEST_LEN'])
        if (len(data) > 0):
            conn.send(data) # send to browser/client
        else:
            break

    然后,我们适当地关闭服务器连接并进行错误处理,以确保服务器按预期工作。


    如何测试服务器?
    1.在终端上运行服务器。使其保持运行并切换到您喜欢的浏览器。
    2.转到浏览器的代理设置,并将代理服务器更改为“ localhost”,并将端口更改为“ 12345″。
    3.现在打开任何HTTP网站(非HTTPS),例如 geeksforgeeks.org!您应该能够访问浏览器上的内容。
    服务器运行后,我们可以监视到客户端的请求。我们可以使用这些数据来监视正在运行的内容,也可以基于该内容开发统计信息。
    我们甚至可以限制对网站的访问或将IP地址列入黑名单。在即将到来的教程中,我们将处理更多此类功能。

    接下来是什么?
    在接下来的教程中,我们将在代理服务器中添加以下功能。
    –将域列入黑名单
    –内容监视
    –日志记录
    – HTTP WebServer + ProxyServer