代理服务器是在client和server之间的一个服务器,一般起到缓存的作用,所以也叫缓存服务器。比如:

A ----(HTTP)----》 B ----(HTTP)----》 C

其中A是客户端,C是服务器端,那么B就是proxy server了,是代理服务器,也是缓存服务器:当A发起请求时要求获得C上的一个文件,需要先经过B,B在自己的文件系统中寻找是否有A所请求的文件,如果有,就发给A,完成一次响应;如果没有,则在B上创建新的HTTP请求,发送到C,并将C的响应缓存到文件中,同时回发给A。

只要代理服务器B上存在A所需要的文件,就不必劳烦C重新发送响应,一定程度上减轻C的压力,同时减少响应时间。

下面我们用socket编程来实现一个简单的代理服务器,功能为:

访问 localhost:8899/helloworld.html 格式的url时,若helloworld.html与proxy server在同一目录下,那么返回这个文件,否则报错

访问 localhost:8899/www.baidu.com 格式的url时,从proxy server的文件系统中查找www.baidu.com的缓存文件,若存在则返还;若不存在则向baidu.com发起HTTP请求,将得到的响应缓存并发给客户端。

其中发送的HTTP请求,由tcp socket实现。

#coding:utf-8
from socket import * # 创建socket,绑定到端口,开始监听
tcpSerPort = 8899
tcpSerSock = socket(AF_INET, SOCK_STREAM) # Prepare a server socket
tcpSerSock.bind(('', tcpSerPort))
tcpSerSock.listen(5) while True:
# 开始从客户端接收请求
print 'Ready to serve...'
tcpCliSock, addr = tcpSerSock.accept()
print 'Received a connection from: ', addr
message = tcpCliSock.recv(4096) # 从请求中解析出filename
print message.split()[1]
filename = message.split()[1].partition("/")[2]
fileExist = "false"
filetouse = "/" + filename
try:
# 检查缓存中是否存在该文件
f = open(filetouse[1:], "r")
outputdata = f.readlines()
fileExist = "true"
print 'File Exists!' # 缓存中存在该文件,把它向客户端发送
tcpCliSock.send("HTTP/1.0 200 OK\r\n\r\n") for i in range(0, len(outputdata)):
tcpCliSock.send(outputdata[i])
print 'Read from cache' # 缓存中不存在该文件,异常处理
except IOError:
print 'File Exist: ', fileExist
if fileExist == "false":
# 在代理服务器上创建一个tcp socket
print 'Creating socket on proxyserver'
c = socket(AF_INET, SOCK_STREAM) hostn = filename.replace("www.", "", 1)
print 'Host Name: ', hostn
try:
# 连接到远程服务器80端口
c.connect((hostn, 80))
print 'Socket connected to port 80 of the host' # 在代理服务器上缓存请求的文件
fileobj = c.makefile('r', 0)
#拼凑http get请求的请求行。注意格式为: "请求方法 URI HTTP版本",空格不能省略!
fileobj.write("GET " + "http://" + filename + " HTTP/1.0\n\n") # Read the response into buffer
buff = 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 i in range(0, len(buff)):
tmpFile.write(buff[i])
tcpCliSock.send(buff[i]) except:
print "Illegal request" else:
# HTTP response message for file not found
# Do stuff here
print 'File Not Found...Stupid Andy'
a = 2
# Close the client and the server sockets
tcpCliSock.close()
# Fill in start.
tcpSerSock.close()
# Fill in end.

ref:《计算机网络:自顶向下方法》第二章 套接字编程作业4

简易代理服务器之python实现的更多相关文章

  1. 简易坦克大战python版

      #! /usr/bin/env python # -*- coding:utf8 -*- ''' *author:wasua *purpose:学习python语言,其中的类以及pygame应用 ...

  2. 高逼格利器之Python闭包与装饰器

    生活在魔都的小明,终于攒够了首付,在魔都郊区买了一套房子:有一天,小明踩了狗屎,中了一注彩票,得到了20w,小明很是欢喜,于是想干脆用这20万来装修房子吧(decoration): 整个装修过程,小明 ...

  3. Python实现简易HTTP服务器

    一.Python3 搭建简易HTTP服务器 python -m http.server 浏览器访问:http://localhost:8000 Python3 cgiserver python -m  ...

  4. Python代码样例列表

    扫描左上角二维码,关注公众账号 数字货币量化投资,回复“1279”,获取以下600个Python经典例子源码 ├─algorithm│       Python用户推荐系统曼哈顿算法实现.py│    ...

  5. python之----------字符编码具体原理

    1.内存和硬盘都是用来存储的. CPU:速度快 硬盘:永久保存 2.文本编辑器存取文件的原理(nodepad++,pycharm,word) 打开编辑器就可以启动一个进程,是在内存中的,所以在编辑器编 ...

  6. python全栈开发-Day6 字符编码

    python全栈开发-Day6 字符编码 一 .了解字符编码的知识储备 一 .计算机基础知识 二 .文本编辑器存取文件的原理(nodepad++,pycharm,word) #1.打开编辑器就打开了启 ...

  7. 第三篇:Python字符编码

    一 .了解字符编码的知识储备 1计算机基础知识 1.2文本编辑器存取文件的原理(nodepat++,Pycharm,word) #.打开编辑器就打开了启动了一个进程,是在内存中的,所以,用编辑器编写的 ...

  8. Python系列之 - 字符编码问题

    1.内存和硬盘都是用来存储的. CPU:速度快 硬盘:永久保存 2.文本编辑器存取文件的原理(nodepad++,pycharm,word) 打开编辑器就可以启动一个进程,是在内存中的,所以在编辑器编 ...

  9. Python实现数据库一键导出为Excel表格

    依赖 Python2711 xlwt MySQLdb 数据库相关 连接 获取字段信息 获取数据 Excel基础 workbook sheet 案例 封装 封装之后 测试结果 总结 数据库数据导出为ex ...

随机推荐

  1. powershell网络钓鱼获取用户密码

    1.powershell网络钓鱼脚本: https://raw.githubusercontent.com/enigma0x3/Invoke-LoginPrompt/master/Invoke-Log ...

  2. 【agc008F】Black Radius

    Portal --> agc008F Solution  这题好神仙啊qwq疯狂orz看懂日文题解的sjk太强啦qwq ​   ​  首先我们要统计的东西,是一个涂黑的连通块,然后我们考虑找一个 ...

  3. 【loj2133】【NOI2015】品酒大会

    Portal --> loj2133 Solution 虽然说这题貌似用后缀树之类的好像会更加简短一点..但是还是因为在智力康复所以就还是用后缀数组好了嗯(哇好感动啊难得那么顺畅写了一道noi的 ...

  4. Linux之多线程20160705

    简单介绍一下多线程的API,线程的概念类似与一个任务或者说一个函数,线程一旦被创建就会运行,具体使用方法可以在Linux下使用man 命令查看: pthread_t:线程ID pthread_attr ...

  5. 如何设置eclipse格式化xml代码时不自动换行

    如何设置eclipse格式化代码时不自动换行 2015年12月23日 09:08:36 qq_20889581 阅读数:3770 标签: eclipse格式化android 更多 个人分类: Ecli ...

  6. Codeforces Round #336 (Div. 2)B 暴力 C dp D 区间dp

    B. Hamming Distance Sum time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  7. git 删除远程仓库的命令

    # 删除远程仓库的命令: git branch -r -d origin/branch-name #其中这条命令必须执行,远程仓库才会删除 git push origin :branch-name # ...

  8. String的indexOf方法

    indexOf(String.indexOf 方法)字符串的IndexOf()方法搜索在该字符串上是否出现了作为参数传递的字符串,如果找到字符串,则返回字符的起始位置 (0表示第一个字符,1表示第二个 ...

  9. Qt ------ QProcess,启动外部进程,进程间通信

    简介: 可用于完成启动外部程序,并与之交互通信. 启动一个进程的名字叫“program”,如果某进程的路径没有设置成环境变量,“program”需要包含路径 如果进程可以接收参数,参数叫“argume ...

  10. golang channel状态表

    如果我们查看该表,可以察觉到在操作中可能产生问题的地方.这里有三个可能导致阻塞的操作,以及三 个可能导致程序恐慌的操作. 乍看之下,通道的使用上限制很多,但在检查了这个限制产生的动机并熟悉 了通道的使 ...