【问题标题】:Cache Proxy Server in PythonPython中的缓存代理服务器
【发布时间】:2016-06-13 09:27:41
【问题描述】:

我有一个家庭作业,其中涉及在 Python 中实现代理缓存服务器。这个想法是在我的本地机器上编写我访问临时文件的网页,然后在请求进入时访问它们(如果它们被存储)。现在代码如下所示:

from socket import *
import sys

def main():
    #Create a server socket, bind it to a port and start listening
    tcpSerSock = socket(AF_INET, SOCK_STREAM) #Initializing socket
    tcpSerSock.bind(("", 8030)) #Binding socket to port
    tcpSerSock.listen(5) #Listening for page requests
    while True:
        #Start receiving data from the client
        print 'Ready to serve...'
        tcpCliSock, addr = tcpSerSock.accept()
        print 'Received a connection from:', addr
        message = tcpCliSock.recv(1024)
        print message

        #Extract the filename from the given message
        print message.split()[1]
        filename = message.split()[1].partition("/")[2]
        print filename
        fileExist = "false"
        filetouse = "/" + filename
        print filetouse

        try: #Check whether the file exists in the cache
            f = open(filetouse[1:], "r")
            outputdata = f.readlines()
            fileExist = "true"
            #ProxyServer finds a cache hit and generates a response message
            tcpCliSock.send("HTTP/1.0 200 OK\r\n")
            tcpCliSock.send("Content-Type:text/html\r\n")
            for data in outputdata:
                tcpCliSock.send(data)
            print 'Read from cache'
        except IOError: #Error handling for file not found in cache
            if fileExist == "false":

                c = socket(AF_INET, SOCK_STREAM) #Create a socket on the proxyserver
                hostn = filename.replace("www.","",1) 
                print hostn
                try:
                    c.connect((hostn, 80)) #https://docs.python.org/2/library/socket.html
                    # Create a temporary file on this socket and ask port 80 for
                    # the file requested by the client
                    fileobj = c.makefile('r', 0)
                    fileobj.write("GET " + "http://" + filename + "HTTP/1.0\r\n")
                    # Read the response into buffer
                    buffr = fileobj.readlines()
                    # Create a new file in the cache for the requested file.
                    # Also send the response in the buffer to client socket and the
                    # corresponding file in the cache
                    tmpFile = open(filename,"wb")
                    for data in buffr:
                        tmpFile.write(data)
                        tcpCliSock.send(data)
                except:
                    print "Illegal request"
            else: #File not found
                print "404: File Not Found"
        tcpCliSock.close() #Close the client and the server sockets

main()

为了测试我的代码,我在本地主机上运行代理缓存并相应地设置我的浏览器代理设置

但是,当我运行此代码并尝试使用 Chrome 访问 google 时,我收到一个错误页面,上面写着 err_empty_response。

使用调试器单步执行代码让我意识到它在这一行失败

c.connect((hostn, 80))

我不知道为什么。任何帮助将不胜感激。

附:我正在使用 Google Chrome、Python 2.7 和 Windows 10 进行测试

【问题讨论】:

  • 切断www. 是危险的。没有www. 的名称也不必解析,也不必解析为与www. 相同的IP 地址。
  • 是的,这是有道理的。不幸的是,删除我删除的部分并不能解决问题
  • 没有。看我的回答。您需要先解析名称。检查documentation for getaddrinfo()

标签: python caching networking tcp proxy


【解决方案1】:

您不能在连接时使用名称。 Connect 需要一个 IP 地址来连接。

您可以使用getaddrinfo() 获取建立连接所需的套接字信息。在我的pure-python-whois 包中,我使用以下代码创建连接:

def _openconn(self, server, timeout, port=None):
    port = port if port else 'nicname'
    try:
        for srv in socket.getaddrinfo(server, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_ADDRCONFIG):
            af, socktype, proto, _, sa = srv
            try:
                c = socket.socket(af, socktype, proto)
            except socket.error:
                c = None
                continue
            try:
                if self.source_addr:
                    c.bind(self.source_addr)
                c.settimeout(timeout)
                c.connect(sa)
            except socket.error:
                c.close()
                c = None
                continue
            break
    except socket.gaierror:
        return False

    return c

请注意,这不是很好的代码,因为循环实际上是无用的,而不是使用不同的替代方案。仅在建立连接后才应断开循环。但是,这应该可以作为使用getaddrinfo()的说明

编辑: 您也没有正确清理您的主机名。当我尝试访问http://www.example.com/ 时,我得到/www.example.com/,这显然无法解决。我建议您使用正则表达式来获取缓存的文件名。

【讨论】:

  • 将行更改为 srv = c.getaddrinfo(filename, 80) 然后 c.connect((srv, 80)) 抛出错误,说套接字对象没有属性 getaddrinfo
  • 您仍然必须确保文件名实际上是主机名。解析时不能在主机名中包含路径。它必须只是一个主机名。
  • 我刚刚通过调用 c.getaddrinfo(("www.google.com", 80)) 对其进行了测试并得到了同样的错误。 _socketobject 对象没有属性 getaddrinfo
  • 我上面的代码不是这样的。在您调用getaddrinfo() 时,c 甚至不应该存在。再看看我的代码示例。
  • 我意识到发生了什么。因为我通过说 from socket import * 来导入套接字并且 getaddrinfo 是静态的,所以我只调用 getaddrinfo 而不是 c.getaddrinfo
猜你喜欢
  • 2016-10-17
  • 2011-01-10
  • 2015-05-19
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多